pax_global_header00006660000000000000000000000064151354557520014526gustar00rootroot0000000000000052 comment=6ed73507dd3970a123e267a50b3ee73392e3b053 gperftools-gperftools-2.18/000077500000000000000000000000001513545575200160265ustar00rootroot00000000000000gperftools-gperftools-2.18/.bazelrc000066400000000000000000000002361513545575200174520ustar00rootroot00000000000000# for some reason bazel puts 10.11 as target osx sdk which fails to do # even basic c++17 things. So we have to fix it here :( build --macos_sdk_version=13.2 gperftools-gperftools-2.18/.clangd000066400000000000000000000003171513545575200172600ustar00rootroot00000000000000--- If: PathMatch: .*stacktrace.*-inl\.h Diagnostics: Suppress: '*' --- If: PathMatch: .*spinlock.*-inl\.h Diagnostics: Suppress: '*' --- Diagnostics: Includes: IgnoreHeader: - config\.h gperftools-gperftools-2.18/.github/000077500000000000000000000000001513545575200173665ustar00rootroot00000000000000gperftools-gperftools-2.18/.github/workflows/000077500000000000000000000000001513545575200214235ustar00rootroot00000000000000gperftools-gperftools-2.18/.github/workflows/ci.yml000066400000000000000000000153341513545575200225470ustar00rootroot00000000000000name: CI on: push: branches: - "*" tags: - "*" pull_request: jobs: test: runs-on: ubuntu-latest steps: - name: Clone uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt update sudo apt install automake autoconf libtool build-essential patch perl libc-bin libunwind-dev - name: Install Go uses: actions/setup-go@v5 with: go-version: 'stable' - name: Install pprof run: | go install github.com/google/pprof@latest echo "PATH=$HOME/go/bin:$PATH" >> $GITHUB_ENV - run: echo GPERFTOOLS_ENSURE_PACKAGE_VERSION=1 >> $GITHUB_ENV - name: Build and test run: | ./autogen.sh ./configure export NUMCPUS=`getconf _NPROCESSORS_ONLN` export MORECPUS="$(($NUMCPUS * 3))" printf "NUMCPUS=%d MORECPUS=%d\n" "$NUMCPUS" "$MORECPUS" make "-j${NUMCPUS}" make "-j${MORECPUS}" check || make "-j${MORECPUS}" recheck # A number of features in gperftools is optional. Lets make # sure that on a common x86/Linux platform all the optional # pieces are actually convigured and built. See # e1f821e56f80ad63d37407267e0022b9ca07a458 for the curious # example of how things could be subtly broken. # # getpc_test is proxy for libprofiler being enabled ./getpc_test # Ensure that debugallocator is present as well. ./tcmalloc_minimal_debug_unittest ./tcmalloc_debug_unittest # Verify that heap profiler is built and works. ./heap-profiler_unittest - name: Upload Test Logs uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: test-logs-${{ github.job }} retention-days: 7 path: | *.log test-i386: runs-on: ubuntu-latest steps: - name: Clone uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt update sudo apt install automake autoconf libtool build-essential patch perl libc-bin g++-multilib - name: Install Go uses: actions/setup-go@v5 with: go-version: 'stable' - name: Install pprof run: | go install github.com/google/pprof@latest echo "PATH=$HOME/go/bin:$PATH" >> $GITHUB_ENV - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 with: key: ${{ github.job }}-${{ matrix.os }} - name: Add ccache to PATH run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV # when testing autotools-based build ensure that we check PACKAGE_VERSION matches versions in tcmalloc.h - run: echo GPERFTOOLS_ENSURE_PACKAGE_VERSION=1 >> $GITHUB_ENV - name: Build and test # GNU/Linux i386 currently fails with libgcc backtracer due to wrong unwind info in memcpy-ia32.S. So we force frame pointers. run: | ./autogen.sh ./configure CXX='g++ -m32' CC='gcc -m32' --enable-frame-pointers export NUMCPUS=`getconf _NPROCESSORS_ONLN` export MORECPUS="$(($NUMCPUS * 3))" printf "NUMCPUS=%d MORECPUS=%d\n" "$NUMCPUS" "$MORECPUS" make "-j${NUMCPUS}" make "-j${MORECPUS}" check || make "-j${MORECPUS}" recheck # Ensure that notable optional features are built and work. ./getpc_test ./tcmalloc_minimal_debug_unittest ./tcmalloc_debug_unittest ./heap-profiler_unittest - name: Upload Test Logs uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: test-logs-${{ github.job }} retention-days: 7 path: | *.log test-cmake: strategy: matrix: os: [macos-latest, ubuntu-latest] build_type: [RelWithDebInfo, Debug] runs-on: ${{ matrix.os }} steps: - name: Clone uses: actions/checkout@v4 - uses: seanmiddleditch/gha-setup-ninja@v5 - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 with: key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.build_type }} - name: Add ccache to PATH run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Install Go uses: actions/setup-go@v5 with: go-version: 'stable' - name: Install pprof run: | go install github.com/google/pprof@latest echo "PATH=$HOME/go/bin:$PATH" >> $GITHUB_ENV PATH=$HOME/go/bin:$PATH which -a pprof - name: mkdir build/ run: cmake -E make_directory ${{runner.workspace}}/build - name: cmake setup working-directory: ${{runner.workspace}}/build run: cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -G Ninja $GITHUB_WORKSPACE - name: cmake build working-directory: ${{runner.workspace}}/build run: ninja -v - name: test working-directory: ${{runner.workspace}}/build run: ctest -j12 --test-dir . || ctest -j12 --test-dir . --rerun-failed - name: Upload Test Logs uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: test-logs-${{ github.job }}-${{ matrix.os }}-${{ matrix.build_type }} retention-days: 7 path: | ${{runner.workspace}}/build/Testing/Temporary/LastTest.log test-cmake-windows: strategy: matrix: os: [windows-latest] build_type: [RelWithDebInfo, Debug] runs-on: ${{ matrix.os }} steps: - name: Clone uses: actions/checkout@v4 - uses: seanmiddleditch/gha-setup-ninja@v5 - name: mkdir build/ run: cmake -E make_directory ${{runner.workspace}}/build - name: cmake setup working-directory: ${{runner.workspace}}/build shell: bash run: | ruby $GITHUB_WORKSPACE/.github/workflows/scripts/msvc-env.rb cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -G Ninja -DGPERFTOOLS_BUILD_HEAP_PROFILER=OFF -Dgperftools_build_minimal=ON $GITHUB_WORKSPACE - name: cmake build working-directory: ${{runner.workspace}}/build shell: bash run: ruby $GITHUB_WORKSPACE/.github/workflows/scripts/msvc-env.rb ninja -v - name: test working-directory: ${{runner.workspace}}/build env: CTEST_PARALLEL_LEVEL: 12 run: ninja -v test - name: Upload Test Logs uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: test-logs-${{ github.job }}-${{ matrix.os }}-${{ matrix.build_type }} retention-days: 7 path: | ${{runner.workspace}}/build/Testing/Temporary/LastTest.log gperftools-gperftools-2.18/.github/workflows/github-pages.yml000066400000000000000000000023671513545575200245350ustar00rootroot00000000000000name: Publish Github Pages on: push: branches: - master workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - run: sudo apt update && sudo apt install asciidoctor - name: Checkout uses: actions/checkout@v4 - run: mkdir _site && cp -v docs/*gif docs/*png docs/*adoc docs/*html _site/ - run: cd _site; for i in *adoc; do echo $i; asciidoctor $i; done - run: ls -lR _site - name: Setup Pages id: pages uses: actions/configure-pages@v5 - name: Upload artifact uses: actions/upload-pages-artifact@v3 deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 gperftools-gperftools-2.18/.github/workflows/scripts/000077500000000000000000000000001513545575200231125ustar00rootroot00000000000000gperftools-gperftools-2.18/.github/workflows/scripts/msvc-env.rb000066400000000000000000000024611513545575200252000ustar00rootroot00000000000000#!/usr/bin/ruby # github docs point here. Maybe eventually we'll be able to discover # it, so that when this path updates we don't have to edit our stuff. BASE = 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise' require 'json' # MSVC and windows stuff is sick. Or maybe I am not aware of # how to do it nicer. So what happens below? # # Well, we need environment variables setup as if vcvars64.bat is run # (the one that does "cmd with visual studio environment whatever # stuff"). "Thanks" to madness of cmd and .bat files I see no other # way than to create .bat file, that will "call" vcvars thingy and # then invoke ruby which will then dump environment variables we # need. Then "outer" script handles unmarshalling and caching this. Dir.chdir(File.dirname(__FILE__)) do h = begin JSON.parse(IO.read("env-cache")) rescue nil end unless h File.open("msvc-env.bat", "w") do |f| f.write(< static void foo(void) __attribute__ ((unused)); void foo(void) { exit(1); } int main() { return 0; }" HAVE___ATTRIBUTE__) check_c_source_compiles("#include void foo(void) __attribute__((aligned(128))); void foo(void) { exit(1); } int main() { return 0; }" HAVE___ATTRIBUTE__ALIGNED_FN) set(CMAKE_EXTRA_INCLUDE_FILES "malloc.h") 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 check_include_file("glob.h" HAVE_GLOB_H) # for heap-profile-table (cleaning up profiles) check_include_file("execinfo.h" HAVE_EXECINFO_H) # for stacktrace check_include_file("sched.h" HAVE_SCHED_H) # for being nice in our spinlock code check_include_file("sys/syscall.h" HAVE_SYS_SYSCALL_H) check_include_file("fcntl.h" HAVE_FCNTL_H) # for tcmalloc_unittest check_include_file("sys/cdefs.h" HAVE_SYS_CDEFS_H) # Where glibc defines __THROW check_include_file("sys/ucontext.h" HAVE_SYS_UCONTEXT_H) check_include_file("ucontext.h" HAVE_UCONTEXT_H) check_include_file("cygwin/signal.h" HAVE_CYGWIN_SIGNAL_H) # ucontext on cywgin check_include_file("asm/ptrace.h" HAVE_ASM_PTRACE_H) # get ptrace macros, e.g. PT_NIP check_include_file("unistd.h" HAVE_UNISTD_H) # We also need /, but we get those from # AC_PC_FROM_UCONTEXT, below. # We override a lot of memory allocation routines, not all of which are # standard. For those the system doesn't declare, we'll declare ourselves. set(CMAKE_REQUIRED_DEFINITIONS -D_XOPEN_SOURCE=600) check_symbol_exists("posix_memalign" "stdlib.h;malloc.h" HAVE_DECL_POSIX_MEMALIGN) check_symbol_exists("memalign" "stdlib.h;malloc.h" HAVE_DECL_MEMALIGN) check_symbol_exists("valloc" "stdlib.h;malloc.h" HAVE_DECL_VALLOC) check_symbol_exists("pvalloc" "stdlib.h;malloc.h" HAVE_DECL_PVALLOC) set(CMAKE_REQUIRED_DEFINITIONS) # We hardcode HAVE_MMAP to 1. There are no interesting systems anymore # without functional mmap. And our windows (except mingw) builds # aren't using autoconf. So we keep HAVE_MMAP define, but only to # distingush windows and rest. if(NOT WIN32) set(HAVE_MMAP 1) endif() if(gperftools_enable_libunwind) check_include_file("libunwind.h" HAVE_LIBUNWIND_H) if(HAVE_LIBUNWIND_H) find_library(libunwind_location NAMES unwind) if(libunwind_location) check_library_exists( unwind backtrace ${libunwind_location} have_libunwind) endif() if(have_libunwind) set(unwind_libs ${libunwind_location}) set(will_use_libunwind ON) set(USE_LIBUNWIND 1) endif() endif() endif() check_c_compiler_flag("-fno-omit-frame-pointer -momit-leaf-frame-pointer" have_omit_leaf_fp) check_c_source_compiles(" #if !(__i386__ || __x86_64__ || __riscv || __aarch64__) #error unsupported arch #endif int main() { return 0; } " use_omit_leaf_fp) if (use_omit_leaf_fp) add_compile_options(-fno-omit-frame-pointer -momit-leaf-frame-pointer) endif() option(gperftools_dynamic_sized_delete_support "Try to build run-time switch for sized delete operator" OFF) if(gperftools_dynamic_sized_delete_support) set(ENABLE_DYNAMIC_SIZED_DELETE 1) endif() option(gperftools_sized_delete "Build sized delete operator" OFF) if(gperftools_sized_delete) set(ENABLE_SIZED_DELETE 1) endif() if(NOT MSVC) set(CMAKE_REQUIRED_FLAGS -fsized-deallocation) check_cxx_source_compiles(" #include int main() { (::operator delete)(0, 256); return 0; }" have_sized_deallocation) set(CMAKE_REQUIRED_FLAGS) endif() check_cxx_source_compiles(" #include int main() { #if __APPLE__ || __FreeBSD__ #error OSX _Unwind_Backtrace recurses back to malloc #endif &_Unwind_Backtrace; return 0; }" HAVE_UNWIND_BACKTRACE) check_cxx_source_compiles(" #include int main() { &__cxxabiv1::__cxa_demangle; }" HAVE_CXA_DEMANGLE) if(enable_backtrace) set(default_emergency_malloc ON) else() set(default_emergency_malloc OFF) endif() if(will_use_libunwind AND ARM) set(default_emergency_malloc ON) endif() option(gperftools_emergency_malloc "Build emergency malloc" ${default_emergency_malloc}) check_c_source_compiles( "int main() { return __builtin_expect(main != 0, 1); }" HAVE_BUILTIN_EXPECT) if(enable_backtrace) check_symbol_exists("backtrace" "execinfo.h" HAVE_DECL_BACKTRACE) check_function_exists("backtrace" backtrace_exists) if(NOT backtrace_exists) set(CMAKE_REQUIRED_LIBRARIES execinfo) check_function_exists("backtrace" backtrace_exists) set(CMAKE_REQUIRED_LIBRARIES) if(backtrace_exists) list(INSERT unwind_libs 0 execinfo) endif() endif() endif() find_package(Threads REQUIRED) link_libraries(Threads::Threads) check_variable_exists("program_invocation_name" HAVE_PROGRAM_INVOCATION_NAME) if(MINGW) check_symbol_exists("sleep" "unistd.h" HAVE_DECL_SLEEP) check_symbol_exists("nanosleep" "time.h" HAVE_DECL_NANOSLEEP) endif() if(LINUX) check_c_source_compiles(" #include #include int main() { return SIGEV_THREAD_ID || CLOCK_THREAD_CPUTIME_ID; }" HAVE_LINUX_SIGEV_THREAD_ID) endif() # Disable large allocation report by default. option(gperftools_enable_large_alloc_report "Report very large allocations to stderr" OFF) set(ENABLE_LARGE_ALLOC_REPORT ${gperftools_enable_large_alloc_report}) # Enable aggressive decommit by default option(gperftools_enable_aggressive_decommit_by_default "Enable aggressive decommit by default" OFF) set(ENABLE_AGGRESSIVE_DECOMMIT_BY_DEFAULT ${gperftools_enable_aggressive_decommit_by_default}) configure_file(cmake/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY) if(GPERFTOOLS_BUILD_CPU_PROFILER OR GPERFTOOLS_BUILD_HEAP_PROFILER) set(WITH_STACK_TRACE ON) endif() include_directories($) # This is so we can #include include_directories($) if(NOT WITH_STACK_TRACE) add_compile_definitions(NO_TCMALLOC_SAMPLES) endif() # These are good warnings to turn on by default. if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare") endif() if(have_sized_deallocation) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation") endif() option( gperftools_enable_frame_pointers "Compile with -fno-omit-frame-pointer (see INSTALL)" OFF) if(gperftools_enable_frame_pointers) add_compile_options(-fno-omit-frame-pointer -DFORCED_FRAME_POINTERS) endif() # On windows when building static library, due to patching, we need to # force "core" of tcmalloc to be linked in to activate patching etc. We # achieve that by telling linker to assume __tcmalloc is not defined. set(TCMALLOC_FLAGS) if(MINGW) list(APPEND TCMALLOC_FLAGS "-Wl,-u__tcmalloc") endif() if(MSVC) list(APPEND TCMALLOC_FLAGS "/INCLUDE:__tcmalloc") endif() add_library(common STATIC src/base/logging.cc src/base/generic_writer.cc src/base/sysinfo.cc src/base/proc_maps_iterator.cc src/base/dynamic_annotations.cc src/base/spinlock.cc src/base/spinlock_internal.cc) add_library(low_level_alloc STATIC src/base/low_level_alloc.cc) if(BUILD_SHARED_LIBS) set_property(TARGET common PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET low_level_alloc PROPERTY POSITION_INDEPENDENT_CODE ON) else() # windows needs this. Doesn't hurt others. # # TODO: make sure we do something with headers. If/when someone uses # statically built tcmalloc_minimal.lib downstream, they need to see # PERFTOOLS_DLL_DECL set to nothing as well. add_compile_definitions(PERFTOOLS_DLL_DECL= ) endif() set(SYSTEM_ALLOC_CC src/system-alloc.cc) set(TCMALLOC_CC src/tcmalloc.cc) if(MINGW OR MSVC) target_sources(common PRIVATE src/windows/port.cc src/windows/ia32_modrm_map.cc src/windows/ia32_opcode_map.cc src/windows/mini_disassembler.cc src/windows/preamble_patcher.cc src/windows/preamble_patcher_with_stub.cc) set(SYSTEM_ALLOC_CC src/windows/system-alloc.cc) set(TCMALLOC_CC src/windows/patch_functions.cc) # patch_function uses -lpsapi and spinlock bits use -synchronization # and -lshlwapi link_libraries(psapi synchronization shlwapi) endif() if(BUILD_TESTING) add_library(gtest STATIC vendor/googletest/googletest/src/gtest_main.cc vendor/googletest/googletest/src/gtest-assertion-result.cc vendor/googletest/googletest/src/gtest-death-test.cc vendor/googletest/googletest/src/gtest-filepath.cc vendor/googletest/googletest/src/gtest-matchers.cc vendor/googletest/googletest/src/gtest-port.cc vendor/googletest/googletest/src/gtest-printers.cc vendor/googletest/googletest/src/gtest-test-part.cc vendor/googletest/googletest/src/gtest-typed-test.cc vendor/googletest/googletest/src/gtest.cc) target_include_directories(gtest PRIVATE $ $) target_include_directories(gtest INTERFACE $) add_executable(low_level_alloc_unittest src/tests/low_level_alloc_unittest.cc) target_compile_definitions(low_level_alloc_unittest PRIVATE NO_TCMALLOC_SAMPLES PERFTOOLS_DLL_DECL= ) target_link_libraries(low_level_alloc_unittest low_level_alloc common gtest) add_test(low_level_alloc_unittest low_level_alloc_unittest) endif() ### ------- stack trace if(WITH_STACK_TRACE) ### Making the library add_library(stacktrace STATIC src/stacktrace.cc src/base/elf_mem_image.cc src/base/vdso_support.cc) target_link_libraries(stacktrace PRIVATE ${unwind_libs}) if(BUILD_SHARED_LIBS) set_property(TARGET stacktrace PROPERTY POSITION_INDEPENDENT_CODE ON) endif() if(BUILD_TESTING) add_executable(stacktrace_unittest src/tests/stacktrace_unittest.cc src/stacktrace.cc src/base/elf_mem_image.cc src/base/vdso_support.cc) target_link_libraries(stacktrace_unittest ${unwind_libs} common gtest) target_compile_definitions(stacktrace_unittest PRIVATE STACKTRACE_IS_TESTED PERFTOOLS_DLL_DECL= ) add_test(stacktrace_unittest stacktrace_unittest) add_executable(check_address_test src/tests/check_address_test.cc) target_link_libraries(check_address_test common gtest) add_test(check_address_test check_address_test) endif() endif() ### ------- tcmalloc_minimal (thread-caching malloc) ### Making the library set(MINIMAL_MALLOC_SRC src/common.cc src/internal_logging.cc ${SYSTEM_ALLOC_CC} src/memfs_malloc.cc src/safe_strerror.cc src/central_freelist.cc src/page_heap.cc src/sampler.cc src/span.cc src/stack_trace_table.cc src/static_vars.cc src/thread_cache.cc src/thread_cache_ptr.cc src/malloc_hook.cc src/malloc_extension.cc) add_library(tcmalloc_minimal ${TCMALLOC_CC} ${MINIMAL_MALLOC_SRC}) if(gperftools_enable_broken_install_targets) install(TARGETS tcmalloc_minimal) endif() target_compile_definitions(tcmalloc_minimal PRIVATE NO_TCMALLOC_SAMPLES) target_link_options(tcmalloc_minimal INTERFACE ${TCMALLOC_FLAGS}) target_link_libraries(tcmalloc_minimal PRIVATE common) if(BUILD_TESTING) add_executable(tcmalloc_minimal_unittest src/tests/tcmalloc_unittest.cc src/tests/testutil.cc) target_link_libraries(tcmalloc_minimal_unittest tcmalloc_minimal gtest) add_test(tcmalloc_minimal_unittest tcmalloc_minimal_unittest) add_executable(tcmalloc_minimal_large_unittest src/tests/tcmalloc_large_unittest.cc src/tests/testutil.cc) target_link_libraries(tcmalloc_minimal_large_unittest tcmalloc_minimal) add_test(tcmalloc_minimal_large_unittest tcmalloc_minimal_large_unittest) add_executable(tcmalloc_minimal_large_heap_fragmentation_unittest src/tests/large_heap_fragmentation_unittest.cc) target_link_libraries( tcmalloc_minimal_large_heap_fragmentation_unittest tcmalloc_minimal gtest) add_test(tcmalloc_minimal_large_heap_fragmentation_unittest tcmalloc_minimal_large_heap_fragmentation_unittest) add_executable(addressmap_unittest src/tests/addressmap_unittest.cc) target_link_libraries(addressmap_unittest common gtest) add_test(addressmap_unittest addressmap_unittest) add_executable(system_alloc_unittest src/tests/system-alloc_unittest.cc) target_link_libraries(system_alloc_unittest tcmalloc_minimal gtest) add_test(system_alloc_unittest system_alloc_unittest) if(NOT MINGW AND NOT MSVC) add_executable(unique_path_unittest src/tests/unique_path_unittest.cc) target_link_libraries(unique_path_unittest common gtest) add_test(unique_path_unittest unique_path_unittest) endif() add_executable(packed_cache_test src/tests/packed-cache_test.cc src/internal_logging.cc) target_compile_definitions(packed_cache_test PRIVATE PERFTOOLS_DLL_DECL= ) target_link_libraries(packed_cache_test common gtest) add_test(packed_cache_test packed_cache_test) add_executable(frag_unittest src/tests/frag_unittest.cc) target_link_libraries(frag_unittest tcmalloc_minimal gtest) add_test(frag_unittest frag_unittest) add_executable(markidle_unittest src/tests/markidle_unittest.cc src/tests/testutil.cc) target_link_libraries(markidle_unittest tcmalloc_minimal gtest) add_test(markidle_unittest markidle_unittest) add_executable(current_allocated_bytes_test src/tests/current_allocated_bytes_test.cc) target_link_libraries(current_allocated_bytes_test tcmalloc_minimal gtest) add_test(current_allocated_bytes_test current_allocated_bytes_test) add_executable(malloc_hook_test src/tests/malloc_hook_test.cc src/malloc_hook.cc src/tests/testutil.cc) target_compile_definitions(malloc_hook_test PRIVATE NO_TCMALLOC_SAMPLES PERFTOOLS_DLL_DECL= ) target_link_libraries(malloc_hook_test common gtest) add_test(malloc_hook_test malloc_hook_test) add_executable(malloc_extension_test src/tests/malloc_extension_test.cc) target_link_libraries(malloc_extension_test tcmalloc_minimal gtest) add_test(malloc_extension_test malloc_extension_test) add_executable(malloc_extension_c_test src/tests/malloc_extension_c_test.cc) target_link_libraries(malloc_extension_c_test tcmalloc_minimal gtest) add_test(malloc_extension_c_test malloc_extension_c_test) if(NOT MINGW AND NOT MSVC AND NOT APPLE) add_executable(memalign_unittest src/tests/memalign_unittest.cc src/tests/testutil.cc) target_link_libraries(memalign_unittest tcmalloc_minimal gtest) add_test(memalign_unittest memalign_unittest) endif() # page heap test is somewhat special it compiles and links entirety # of tcmalloc statically. We'll eventually make it right. add_executable(page_heap_test src/tests/page_heap_test.cc ${TCMALLOC_CC} ${MINIMAL_MALLOC_SRC}) target_compile_definitions(page_heap_test PRIVATE NO_TCMALLOC_SAMPLES PERFTOOLS_DLL_DECL= ) target_link_libraries(page_heap_test common gtest) add_test(page_heap_test page_heap_test) add_executable(pagemap_unittest src/tests/pagemap_unittest.cc src/internal_logging.cc) target_compile_definitions(pagemap_unittest PRIVATE PERFTOOLS_DLL_DECL= ) target_link_libraries(pagemap_unittest common gtest) add_test(pagemap_unittest pagemap_unittest) add_executable(safe_strerror_test src/tests/safe_strerror_test.cc src/safe_strerror.cc) target_link_libraries(safe_strerror_test common gtest) add_test(safe_strerror_test safe_strerror_test) add_executable(cleanup_test src/tests/cleanup_test.cc) target_link_libraries(cleanup_test gtest) add_test(cleanup_test cleanup_test) add_executable(function_ref_test src/tests/function_ref_test.cc) target_link_libraries(function_ref_test gtest) add_test(function_ref_test function_ref_test) add_executable(trivialre_test benchmark/trivialre_test.cc) target_link_libraries(trivialre_test gtest) add_test(trivialre_test trivialre_test) add_executable(generic_writer_test src/tests/generic_writer_test.cc) target_link_libraries(generic_writer_test common gtest) add_test(generic_writer_test generic_writer_test) add_executable(proc_maps_iterator_test src/tests/proc_maps_iterator_test.cc) target_link_libraries(proc_maps_iterator_test common gtest) add_test(proc_maps_iterator_test proc_maps_iterator_test) add_executable(for_each_line_test src/tests/for_each_line_test.cc) target_link_libraries(for_each_line_test common gtest) add_test(for_each_line_test for_each_line_test) add_executable(realloc_unittest src/tests/realloc_unittest.cc) target_link_libraries(realloc_unittest tcmalloc_minimal gtest) add_test(realloc_unittest realloc_unittest) add_executable(stack_trace_table_test src/tests/stack_trace_table_test.cc src/stack_trace_table.cc src/internal_logging.cc) target_compile_definitions(stack_trace_table_test PRIVATE STACK_TRACE_TABLE_IS_TESTED PERFTOOLS_DLL_DECL= ) target_link_libraries(stack_trace_table_test common gtest) add_test(stack_trace_table_test stack_trace_table_test) add_executable(thread_dealloc_unittest src/tests/thread_dealloc_unittest.cc src/tests/testutil.cc) target_link_libraries(thread_dealloc_unittest tcmalloc_minimal) add_test(thread_dealloc_unittest thread_dealloc_unittest) add_executable(min_per_thread_cache_size_test src/tests/min_per_thread_cache_size_test.cc) target_link_libraries(min_per_thread_cache_size_test tcmalloc_minimal gtest) add_test(min_per_thread_cache_size_test min_per_thread_cache_size_test) endif() ### ------- tcmalloc_minimal_debug (thread-caching malloc with debugallocation) if(GPERFTOOLS_BUILD_DEBUGALLOC) add_library(libbacktrace STATIC vendor/libbacktrace-integration/file-format.c vendor/libbacktrace/dwarf.c vendor/libbacktrace/fileline.c vendor/libbacktrace/posix.c vendor/libbacktrace/sort.c vendor/libbacktrace/state.c vendor/libbacktrace/read.c) target_include_directories(libbacktrace BEFORE PRIVATE $ $) add_library(symbolize STATIC src/symbolize.cc vendor/libbacktrace-integration/backtrace-alloc.cc) target_link_libraries(symbolize PRIVATE libbacktrace) if(BUILD_SHARED_LIBS) set_property(TARGET libbacktrace PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET symbolize PROPERTY POSITION_INDEPENDENT_CODE ON) endif() add_library(tcmalloc_minimal_debug src/debugallocation.cc ${MINIMAL_MALLOC_SRC}) if(gperftools_enable_broken_install_targets) install(TARGETS tcmalloc_minimal_debug) endif() target_compile_definitions(tcmalloc_minimal_debug PRIVATE NO_TCMALLOC_SAMPLES) target_link_libraries(tcmalloc_minimal_debug PRIVATE symbolize low_level_alloc common) ### Unittests if(BUILD_TESTING) add_executable(tcmalloc_minimal_debug_unittest src/tests/tcmalloc_unittest.cc src/tests/testutil.cc) target_link_libraries(tcmalloc_minimal_debug_unittest tcmalloc_minimal_debug gtest) add_test(tcmalloc_minimal_debug_unittest tcmalloc_minimal_debug_unittest) add_executable(malloc_extension_debug_test src/tests/malloc_extension_test.cc) target_link_libraries(malloc_extension_debug_test tcmalloc_minimal_debug gtest) add_test(malloc_extension_debug_test malloc_extension_debug_test) if(NOT MINGW AND NOT APPLE) add_executable(memalign_debug_unittest src/tests/memalign_unittest.cc src/tests/testutil.cc) target_link_libraries(memalign_debug_unittest tcmalloc_minimal_debug gtest) add_test(memalign_debug_unittest memalign_debug_unittest) endif() add_executable(realloc_debug_unittest src/tests/realloc_unittest.cc) target_link_libraries(realloc_debug_unittest PUBLIC tcmalloc_minimal_debug gtest) add_test(realloc_debug_unittest realloc_debug_unittest) if(WITH_STACK_TRACE) add_executable(debugallocation_test src/tests/debugallocation_test.cc) target_link_libraries(debugallocation_test tcmalloc_debug gtest) add_test(debugallocation_test debugallocation_test) endif() endif() endif() if(NOT MINGW AND NOT MSVC) if(gperftools_build_benchmark) add_library(run_benchmark benchmark/run_benchmark.cc) add_executable(malloc_bench benchmark/malloc_bench.cc) target_link_libraries(malloc_bench tcmalloc_minimal run_benchmark) if(GPERFTOOLS_BUILD_HEAP_PROFILER) add_executable(malloc_bench_shared_full benchmark/malloc_bench.cc) target_link_libraries(malloc_bench_shared_full run_benchmark tcmalloc) endif() add_executable(binary_trees benchmark/binary_trees.cc) target_link_libraries(binary_trees tcmalloc_minimal) add_executable(binary_trees_shared benchmark/binary_trees.cc) target_link_libraries(binary_trees_shared tcmalloc_minimal) endif() endif() ### ------- tcmalloc (thread-caching malloc + heap profiler) if(GPERFTOOLS_BUILD_HEAP_PROFILER) if(gperftools_emergency_malloc) set(EMERGENCY_MALLOC_CC src/emergency_malloc.cc) set(EMERGENCY_MALLOC_DEFINE ENABLE_EMERGENCY_MALLOC) else() set(EMERGENCY_MALLOC_CC ) endif() ### Making the library set(FULL_MALLOC_SRC ${MINIMAL_MALLOC_SRC} src/heap-profile-table.cc src/heap-profiler.cc ${EMERGENCY_MALLOC_CC} src/malloc_backtrace.cc src/heap-checker-stub.cc) add_library(tcmalloc ${TCMALLOC_CC} ${FULL_MALLOC_SRC}) if(gperftools_enable_broken_install_targets) install(TARGETS tcmalloc) endif() target_compile_definitions(tcmalloc PRIVATE ${EMERGENCY_MALLOC_DEFINE}) target_link_libraries(tcmalloc PRIVATE stacktrace low_level_alloc common) target_link_options(tcmalloc INTERFACE ${TCMALLOC_FLAGS}) ### Unittests if(BUILD_TESTING) add_executable(tcmalloc_unittest src/tests/tcmalloc_unittest.cc src/tests/testutil.cc) target_link_libraries(tcmalloc_unittest tcmalloc gtest) add_test(tcmalloc_unittest tcmalloc_unittest) add_executable(tcmalloc_large_unittest src/tests/tcmalloc_large_unittest.cc) target_link_libraries(tcmalloc_large_unittest tcmalloc) add_test(tcmalloc_large_unittest tcmalloc_large_unittest) add_executable(tcmalloc_large_heap_fragmentation_unittest src/tests/large_heap_fragmentation_unittest.cc) target_link_libraries(tcmalloc_large_heap_fragmentation_unittest tcmalloc gtest) add_test(tcmalloc_large_heap_fragmentation_unittest tcmalloc_large_heap_fragmentation_unittest) add_executable(heap_checker_stub_test src/tests/heap-checker-stub-test.cc) target_link_libraries(heap_checker_stub_test tcmalloc) add_test(heap_checker_stub_test heap_checker_stub_test) add_executable(sampler_test src/tests/sampler_test.cc src/sampler.cc src/base/spinlock.cc src/base/spinlock_internal.cc src/base/sysinfo.cc src/base/logging.cc) target_link_libraries(sampler_test gtest) add_test(sampler_test sampler_test) # These unittests often need to run binaries. They're in the current dir list(APPEND TESTS_ENVIRONMENT BINDIR=. TMPDIR=/tmp/perftools) set(sampling_test_SOURCES src/tests/sampling_test.cc) add_executable(sampling_test src/tests/sampling_test.cc) target_link_libraries(sampling_test tcmalloc) add_test(sampling_test sampling_test) if(GPERFTOOLS_BUILD_HEAP_PROFILER) add_executable(heap-profiler_unittest src/tests/heap-profiler_unittest.cc) target_link_libraries(heap-profiler_unittest tcmalloc) add_test(NAME heap-profiler_unittest.sh COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/src/tests/heap-profiler_unittest.sh" "${CMAKE_CURRENT_BINARY_DIR}/heap-profiler_unittest") endif() endif() endif() ### ------- tcmalloc with debugallocation if(GPERFTOOLS_BUILD_DEBUGALLOC) if(GPERFTOOLS_BUILD_HEAP_PROFILER) add_library(tcmalloc_debug src/debugallocation.cc ${FULL_MALLOC_SRC}) if(gperftools_enable_broken_install_targets) install(TARGETS tcmalloc_debug) endif() target_compile_definitions(tcmalloc_debug PRIVATE ${EMERGENCY_MALLOC_DEFINE}) target_link_libraries(tcmalloc_debug PRIVATE symbolize low_level_alloc stacktrace common) ### Unittests if(BUILD_TESTING) add_executable(tcmalloc_debug_unittest src/tests/tcmalloc_unittest.cc src/tests/testutil.cc) target_link_libraries(tcmalloc_debug_unittest tcmalloc_debug gtest) add_test(tcmalloc_debug_unittest tcmalloc_debug_unittest) add_executable(sampling_debug_test src/tests/sampling_test.cc) target_link_libraries(sampling_debug_test tcmalloc_debug) add_test(sampling_debug_test sampling_debug_test) if(GPERFTOOLS_BUILD_HEAP_PROFILER) add_executable(heap-profiler_debug_unittest src/tests/heap-profiler_unittest.cc) target_link_libraries(heap-profiler_debug_unittest tcmalloc_debug) add_test(heap-profiler_debug_unittest.sh "${CMAKE_CURRENT_SOURCE_DIR}/src/tests/heap-profiler_unittest.sh" "${CMAKE_CURRENT_BINARY_DIR}/heap-profiler_debug_unittest") endif() endif() endif() endif() ### ------- CPU profiler if(GPERFTOOLS_BUILD_CPU_PROFILER) add_library(profiler src/profiler.cc src/profile-handler.cc src/profiledata.cc) if(gperftools_enable_broken_install_targets) install(TARGETS profiler) endif() target_link_libraries(profiler PRIVATE stacktrace common) if(BUILD_TESTING) add_executable(getpc_test src/tests/getpc_test.cc) add_test(getpc_test getpc_test) add_executable(profiledata_unittest src/tests/profiledata_unittest.cc src/profiledata.cc) target_link_libraries(profiledata_unittest stacktrace common gtest) add_test(profiledata_unittest profiledata_unittest) add_executable(profile_handler_unittest src/tests/profile-handler_unittest.cc src/profile-handler.cc) target_link_libraries(profile_handler_unittest stacktrace common gtest) add_test(profile_handler_unittest profile_handler_unittest) add_test(NAME profiler_unittest.sh COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/src/tests/profiler_unittest.sh") add_executable(profiler_unittest src/tests/profiler_unittest.cc src/tests/testutil.h src/tests/testutil.cc) target_link_libraries(profiler_unittest PRIVATE profiler) endif() endif() if(BUILD_TESTING) get_directory_property(tests TESTS) message("TESTS_ENVIRONMENT:${TESTS_ENVIRONMENT}") if(TESTS_ENVIRONMENT) foreach(test IN LISTS tests) set_tests_properties(${test} PROPERTIES ENVIRONMENT "${TESTS_ENVIRONMENT}") endforeach() endif() endif() if(MSVC) add_subdirectory(src/windows) endif() message(WARNING "note: gperftools' cmake support is incomplete and is best-effort only") gperftools-gperftools-2.18/COPYING000066400000000000000000000027071513545575200170670ustar00rootroot00000000000000Copyright (c) 2005, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. gperftools-gperftools-2.18/ChangeLog.old000066400000000000000000001032561513545575200203640ustar00rootroot00000000000000Fri Feb 03 15:40:45 2012 Google Inc. * gperftools: version 2.0 * Renamed the project from google-perftools to gperftools (csilvers) * Renamed the .deb/.rpm packagse from google-perftools to gperftools too * Renamed include directory from google/ to gperftools/ (csilvers) * Changed the 'official' perftools email in setup.py/etc * Renamed google-perftools.sln to gperftools.sln * PORTING: Removed bash-isms & grep -q in heap-checker-death_unittest.sh * Changed copyright text to reflect Google's relinquished ownership Tue Jan 31 10:43:50 2012 Google Inc. * google-perftools: version 1.10 release * PORTING: Support for patching assembly on win x86_64! (scott.fr...) * PORTING: Work around atexit-execution-order bug on freebsd (csilvers) * PORTING: Patch _calloc_crt for windows (roger orr) * PORTING: Add C++11 compatibility method for stl allocator (jdennett) * PORTING: use MADV_FREE, not MADV_DONTNEED, on freebsd (csilvers) * PORTING: Don't use SYS_open when not supported on solaris (csilvers) * PORTING: Do not assume uname() returns 0 on success (csilvers) * LSS: Improved ARM support in linux-syscall-support (dougkwan) * LSS: Get rid of unused syscalls in linux-syscall-support (csilvers) * LSS: Fix broken mmap wrapping for ppc (markus) * LSS: Emit .cfi_adjust_cfa_offset when appropriate (ppluzhnikov) * LSS: Be more accurate in register use in __asm__ (markus) * LSS: Fix __asm__ calls to compile under clang (chandlerc) * LSS: Fix ARM inline assembly bug around r7 and swi (lcwu) * No longer log when an allocator fails (csilvers) * void* -> const void* for MallocExtension methods (llib) * Improve HEAP_PROFILE_MMAP and fix bugs with it (dmikurube) * Replace int-based abs with more correct fabs in a test (pmurin) Thu Dec 22 16:22:45 2011 Google Inc. * google-perftools: version 1.9 release * Lightweight check for double-frees (blount) * BUGFIX: Fix pprof to exit properly if run with no args (dagitses) * Suggest ASan as a way to diagnose buggy code (ppluzhnikov) * Get rid of unused CACHELINE_SIZE (csilvers) * Replace atexit() calls with global dtors; helps freebsd (csilvers) * Disable heap-checker under AddressSanitizer (kcc) * Fix bug in powerpc stacktracing (ppluzhnikov) * PERF: Use exponential backoff waiting for spinlocks (m3b) * Fix 64-bit nm on 32-bit binaries in pprof (csilvers) * Add ProfileHandlerDisallowForever (rsc) * BUGFIX: Shell escape when forking in pprof (csilvers) * No longer combine overloaded functions in pprof (csilvers) * Fix address-normalizing bug in pprof (csilvers) * More consistently call abort() instead of exit() on failure (csilvers) * Allow NoGlobalLeaks to be safely called more than once (csilvers) * PORTING/BUGFIX: Fix ARM cycleclock to use volatile asm (dougkwan) * PORTING: 64-bit atomic ops for ARMv7 (dougkwan) * PORTING: Implement stacktrace for ARM (dougkwan) * PORTING: Fix malloc_hook_mmap_linux for ARM (dougkwan) * PORTING: Update linux_syscall_support.h for ARM/etc (evannier, sanek) * PORTING: Fix freebsd to work on x86_64 (chapp...@gmail.com) * PORTING: Added additional SYS_mmap fixes for FreeBSD (chappedm) * PORTING: Allow us to compile on OS X 10.6 and run on 10.5 (raltherr) * PORTING: Check for mingw compilers that *do* define timespec * PORTING: Add "support" for MIPS cycletimer * PORTING: Fix fallback cycle-timer to work with Now (dougkwan) * PERF: Move stack trace collecting out of the mutex (taylorc) * PERF: Get the deallocation stack trace outside the mutex (sean) * Make PageHeap dynamically allocated for leak checks (maxim) * BUGFIX: Fix probing of nm -f behavior in pprof (dpeng) * BUGFIX: Fix a race with the CentralFreeList lock before main (sanjay) * Support /pprof/censusprofile url arguments (rajatjain) * Change IgnoreObject to return its argument (nlewycky) * Update malloc-hook files to support more CPUs * BUGFIX: write our own strstr to avoid libc problems (csilvers) * Use simple callgrind compression facility in pprof * Print an error message when we can't run pprof to symbolize (csilvers) * Die in configure when g++ is't installed (csilvers) * DOC: Beef up the documentation a bit about using libunwind (csilvers) Fri Aug 26 13:29:25 2011 Google Inc. * google-perftools: version 1.8.3 release * Added back the 'pthreads unsafe early' #define, needed for FreeBSD Thu Aug 11 15:01:47 2011 Google Inc. * google-perftools: version 1.8.2 release * Fixed calculation of patchlevel, 'make check' should all pass again Tue Jul 26 20:57:51 2011 Google Inc. * google-perftools: version 1.8.1 release * Added an #include to fix compile breakage on latest gcc's * Removed an extra , in the configure.ac script Fri Jul 15 16:10:51 2011 Google Inc. * google-perftools: version 1.8 release * PORTING: (Disabled) support for patching mmap on freebsd (chapp...) * PORTING: Support volatile __malloc_hook for glibc 2.14 (csilvers) * PORTING: Use _asm rdtsc and __rdtsc to get cycleclock in windows (koda) * PORTING: Fix fd vs. HANDLE compiler error on cygwin (csilvers) * PORTING: Do not test memalign or double-linking on OS X (csilvers) * PORTING: Actually enable TLS on windows (jontra) * PORTING: Some work to compile under Native Client (krasin) * PORTING: deal with pthread_once w/o -pthread on freebsd (csilvers) * Rearrange libc-overriding to make it easier to port (csilvers) * Display source locations in pprof disassembly (sanjay) * BUGFIX: Actually initialize allocator name (mec) * BUGFIX: Keep track of 'overhead' bytes in malloc reporting (csilvers) * Allow ignoring one object twice in the leak checker (glider) * BUGFIX: top10 in pprof should print 10 lines, not 11 (rsc) * Refactor vdso source files (tipp) * Some documentation cleanups * Document MAX_TOTAL_THREAD_CACHE_SIZE <= 1Gb (nsethi) * Add MallocExtension::GetOwnership(ptr) (csilvers) * BUGFIX: We were leaving out a needed $(top_srcdir) in the Makefile * PORTING: Support getting argv0 on OS X * Add 'weblist' command to pprof: like 'list' but html (sanjay) * Improve source listing in pprof (sanjay) * Cap cache sizes to reduce fragmentation (ruemmler) * Improve performance by capping or increasing sizes (ruemmler) * Add M{,un}mapReplacmenet hooks into MallocHook (ribrdb) * Refactored system allocator logic (gangren) * Include cleanups (csilvers) * Add TCMALLOC_SMALL_BUT_SLOW support (ruemmler) * Clarify that tcmalloc stats are MiB (robinson) * Remove support for non-tcmalloc debugallocation (blount) * Add a new test: malloc_hook_test (csilvers) * Change the configure script to be more crosstool-friendly (mcgrathr) * PORTING: leading-underscore changes to support win64 (csilvers) * Improve debugallocation tc_malloc_size (csilvers) * Extend atomicops.h and cyceclock to use ARM V6+ optimized code (sanek) * Change malloc-hook to use a list-like structure (llib) * Add flag to use MAP_PRIVATE in memfs_malloc (gangren) * Windows support for pprof: nul and /usr/bin/file (csilvers) * TESTING: add test on strdup to tcmalloc_test (csilvers) * Augment heap-checker to deal with no-inode maps (csilvers) * Count .dll/.dylib as shared libs in heap-checker (csilvers) * Disable sys_futex for arm; it's not always reliable (sanek) * PORTING: change lots of windows/port.h macros to functions * BUGFIX: Generate correct version# in tcmalloc.h on windows (csilvers) * PORTING: Some casting to make solaris happier about types (csilvers) * TESTING: Disable debugallocation_test in 'minimal' mode (csilvers) * Rewrite debugallocation to be more modular (csilvers) * Don't try to run the heap-checker under valgrind (ppluzhnikov) * BUGFIX: Make focused stat %'s relative, not absolute (sanjay) * BUGFIX: Don't use '//' comments in a C file (csilvers) * Quiet new-gcc compiler warnings via -Wno-unused-result, etc (csilvers) Fri Feb 04 15:54:31 2011 Google Inc. * google-perftools: version 1.7 release * Reduce page map key size under x86_64 by 4.4MB (rus) * Remove a flaky malloc-extension test (fdabek) * Improve the performance of PageHeap::New (ond..., csilvers) * Improve sampling_test with no-inline additions/etc (fdabek) * 16-byte align debug allocs (jyasskin) * Change FillProcSelfMaps to detect out-of-buffer-space (csilvers) * Document the need for sampling to use GetHeapSample (csilvers) * Try to read TSC frequency from tsc_freq_khs (adurbin) * Do better at figuring out if tests are running under gdb (ppluzhnikov) * Improve spinlock contention performance (ruemmler) * Better internal-function list for pprof's /contention (ruemmler) * Speed up GoogleOnce (m3b) * Limit number of incoming/outgoing edges in pprof (sanjay) * Add pprof --evince to go along with --gv (csilvers) * Document the various ways to get heap-profiling information (csilvers) * Separate out synchronization profiling routines (ruemmler) * Improve malloc-stats output to be more understandable (csilvers) * Add support for census profiler in pporf (nabeelmian) * Document how pprof's /symbol must support GET requests (csilvers) * Improve acx_pthread.m4 (ssuomi, liujisi) * Speed up pprof's ExtractSymbols (csilvers) * Ignore some known-leaky (java) libraries in the heap checker (davidyu) * Make kHideMask use all 64 bits in tests (ppluzhnikov) * Clean up pprof input-file handling (csilvers) * BUGFIX: Don't crash if __environ is NULL (csilvers) * BUGFIX: Fix totally broken debugallocation tests (csilvers) * BUGFIX: Fix up fake_VDSO handling for unittest (ppluzhnikov) * BUGFIX: Suppress all large allocs when report threshold is 0 (lexie) * BUGFIX: mmap2 on i386 takes an off_t, not off64_t (csilvers) * PORTING: Add missing PERFTOOLS_DLL_DECL (csilvers) * PORTING: Add stddef.h to make newer gcc's happy (csilvers) * PORTING: Document some tricks for working under OS X (csilvers) * PORTING: Don't try to check valgrind for windows (csilvers) * PORTING: Make array-size a var to compile under clang (chandlerc) * PORTING: No longer hook _aligned_malloc and _aligned_free (csilvers) * PORTING: Quiet some gcc warnings (csilvers) * PORTING: Replace %PRIxPTR with %p to be more portable (csilvers) * PORTING: Support systems that capitalize /proc weirdly (sanek) * PORTING: Treat arm3 the same as arm5t in cycletimer (csilvers) * PORTING: Update windows logging to not allocate memory (csilvers) * PORTING: avoid double-patching newer windows DLLs (roger.orr) * PORTING: get dynamic_annotations.c to work on windows (csilvers) * Add pkg-config .pc files for the 5 libraries we produce (csilvers) * Added proper libtool versioning, so this lib will be 0.1.0 (csilvers) * Moved from autoconf 2.64 to 2.65 Thu Aug 5 12:48:03 PDT 2010 Google Inc. * google-perftools: version 1.6 release * Add tc_malloc_usable_size for compatibility with glibc (csilvers) * Override malloc_usable_size with tc_malloc_usable_size (csilvers) * Default to no automatic heap sampling in tcmalloc (csilvers) * Add -DTCMALLOC_LARGE_PAGES, a possibly faster tcmalloc (rus) * Make some functions extern "C" to avoid false ODR warnings (jyasskin) * pprof: Add SVG-based output (rsc) * pprof: Extend pprof --tools to allow per-tool configs (csilvers) * pprof: Improve support of 64-bit and big-endian profiles (csilvers) * pprof: Add interactive callgrind suport (weidenri...) * pprof: Improve address->function mapping a bit (dpeng) * Better detection of when we're running under valgrind (csilvers) * Better CPU-speed detection under valgrind (saito) * Use, and recommend, -fno-builtin-malloc when compiling (csilvers) * Avoid false-sharing of memory between caches (bmaurer) * BUGFIX: Fix heap sampling to use correct alloc size (bmauer) * BUGFIX: Avoid gcc 4.0.x bug by making hook-clearing atomic (csilvers) * BUGFIX: Avoid gcc 4.5.x optimization bug (csilvers) * BUGFIX: Work around deps-determining bug in libtool 1.5.26 (csilvers) * BUGFIX: Fixed test to use HAVE_PTHREAD, not HAVE_PTHREADS (csilvers) * BUGFIX: Fix tls callback behavior on windows when using wpo (wtc) * BUGFIX: properly align allocation sizes on Windows (antonm) * BUGFIX: Fix prototypes for tcmalloc/debugalloc wrt throw() (csilvers) * DOC: Updated heap-checker doc to match reality better (fischman) * DOC: Document ProfilerFlush, ProfilerStartWithOptions (csilvers) * DOC: Update docs for heap-profiler functions (csilvers) * DOC: Clean up documentation around tcmalloc.slack_bytes (fikes) * DOC: Renamed README.windows to README_windows.txt (csilvers) * DOC: Update the NEWS file to be non-empty (csilvers) * PORTING: Fix windows addr2line and nm with proper rc code (csilvers) * PORTING: Add CycleClock and atomicops support for arm 5 (sanek) * PORTING: Improve PC finding on cygwin and redhat 7 (csilvers) * PORTING: speed up function-patching under windows (csilvers) Tue Jan 19 14:46:12 2010 Google Inc. * google-perftools: version 1.5 release * Add tc_set_new_mode (willchan) * Make memalign functions + realloc respect tc_set_new_mode (willchan) * Add ReleaseToSystem(num_bytes) (kash) * Handle zero-length symbols a bit better in pprof (csilvers) * Prefer __environ to /proc/self/environ in cpu profiler (csilvers) * Add HEAP_CHECK_MAX_LEAKS flag to control #leaks to report (glider) * Add two new numeric pageheap properties to MallocExtension (fikes) * Print alloc size when mmap fails (hakon) * Add ITIMER_REAL support to cpu profiler (csilvers, nabeelmian) * Speed up symbolizer in heap-checker reporting (glider) * Speed up futexes with FUTEX_PRIVATE_FLAG (m3b) * Speed up tcmalloc but doing better span coalescing (sanjay) * Better support for different wget's and addr2maps in pprof (csilvres) * Implement a nothrow version of delete and delete[] (csilvers) * BUGFIX: fix a race on module_libcs[i] in windows patching (csilvers) * BUGFIX: Fix debugallocation to call cpp_alloc for new (willchan) * BUGFIX: A simple bugfix for --raw mode (mrabkin) * BUGFIX: Fix C shims to actually be valid C (csilvers) * BUGFIX: Fix recursively-unmapped-region accounting (ppluzhnikov) * BUGFIX: better distinguish real and fake vdso (ppluzhnikov) * WINDOWS: replace debugmodule with more reliable psai (andrey) * PORTING: Add .bundle as another shared library extension (csilvers) * PORTING: Fixed a typo bug in the ocnfigure PRIxx m4 macro (csilvers) * PORTING: Augment sysinfo to work on 64-bit OS X (csilvers) * PORTING: Use sys/ucontext.h to fix compiing on OS X 10.6 (csilvers) * PORTING: Fix sysinfo libname reporting for solaris x86 (jeffrey) * PORTING: Use libunwind for i386 when using --omitfp (ppluzhnikov) Thu Sep 10 13:51:15 2009 Google Inc. * google-perftools: version 1.4 release * Add debugallocation library, to catch memory leaks, stomping, etc * Add --raw mode to allow for delayed processing of pprof files * Use less memory when reading CPU profiles * New environment variables to control kernel-allocs (sbrk, memfs, etc) * Add MarkThreadBusy(): performance improvement * Remove static thread-cache-size code; all is dynamic now * Add new HiddenPointer class to heap checker * BUGFIX: pvalloc(0) allocates now (found by new debugalloc library) * BUGFIX: valloc test (not implementation) no longer overruns memory * BUGFIX: GetHeapProfile no longer deadlocks * BUGFIX: Support unmapping memory regions before main * BUGFIX: Fix some malloc-stats formatting * BUGFIX: Don't crash as often when freeing libc-allocated memory * BUGFIX: Deal better with incorrect PPROF_PATH when symbolizing * BUGFIX: weaken new/delete/etc in addition to malloc/free/etc * BUGFIX: Fix return value of GetAllocatedSize * PORTING: Fix mmap-#define problem on some 64-bit systems * PORTING: Call ranlib again (some OS X versions need it) * PORTING: Fix a leak when building with LLVM * PORTING: Remove some unneeded bash-ishs from testing scripts * WINDOWS: Support library unloading as well as loading * WINDOWS/BUGFIX: Set page to 'xrw' instead of 'rw' when patching Tue Jun 9 18:19:06 2009 Google Inc. * google-perftools: version 1.3 release * Provide our own name for memory functions: tc_malloc, etc (csilvers) * Weaken memory-alloc functions so user can override them (csilvers) * Remove meaningless delete(nothrow) and delete[](nothrow) (csilvers) * BUILD: replace clever libtcmalloc/profiler.a with a new .a (csilvers) * PORTING: improve windows port by using google spinlocks (csilvers) * PORTING: Fix RedHat 9 memory allocation in heapchecker (csilvers) * PORTING: Rename OS_WINDOWS macro to PLATFORM_WINDOWS (mbelshe) * PORTING/BUGFIX: Make sure we don't clobber GetLastError (mbelshe) * BUGFIX: get rid of useless data for callgrind (weidenrinde) * BUGFIX: Modify windows patching to deadlock sometimes (csilvers) * BUGFIX: an improved fix for hook handling during fork (csilvers) * BUGFIX: revamp profiler_unittest.sh, which was very broken (csilvers) Fri Apr 17 16:40:48 2009 Google Inc. * google-perftools: version 1.2 release * Allow large_alloc_threshold=0 to turn it off entirely (csilvers) * Die more helpfully when out of memory for internal data (csilvers) * Refactor profile-data gathering, add a new unittest (cgd, nabeelmian) * BUGFIX: fix rounding errors with static thread-size caches (addi) * BUGFIX: disable hooks better when forking in leak-checker (csilvers) * BUGFIX: fix realloc of crt pointers on windows (csilvers) * BUGFIX: do a better job of finding binaries in .sh tests (csilvers) * WINDOWS: allow overriding malloc/etc instead of patching (mbelshe) * PORTING: fix compilation error in a ppc-specific file (csilvers) * PORTING: deal with quirks in cygwin's /proc/self/maps (csilvers) * PORTING: use 'A' version of functions for ascii input (mbelshe) * PORTING: generate .so's on cygwin and mingw (ajenjo) * PORTING: disable profiler methods on cygwin (jperkins) * Updated autoconf version to 2.61 and libtool version to 1.5.26 Wed Mar 11 11:25:34 2009 Google Inc. * google-perftools: version 1.1 release * Dynamically resize thread caches -- nice perf. improvement (kash) * Add VDSO support to give better stacktraces in linux (ppluzhnikov) * Improve heap-profiling sampling algorithm (ford) * Rewrite leak-checking code: should be faster and more robust (sanjay) * Use ps2 instead of ps for dot: better page cropping for gv (csilvers) * Disable malloc-failure warning messages by default (csilvers) * Update config/Makefile to disable tests on a per-OS basis (csilvers) * PORTING: Get perftools compiling under MSVC 7.1 again (csilvers) * PORTING: Get perftools compiling under cygwin again (csilvers) * PORTING: automatically set library flags for solaris x86 (csilvers) * Add TCMALLOC_SKIP_SBRK to mirror TCMALLOC_SKIP_MMAP (csilvers) * Add --enable flags to allow selective building (csilvers) * Put addr2line-pdb and nm-pdb in proper output directory (csilvers) * Remove deprecated DisableChecksIn (sanjay) * DOCUMENTATION: Document most MallocExtension routines (csilvers) Tue Jan 6 13:58:56 2009 Google Inc. * google-perftools: version 1.0 release * Exactly the same as 1.0rc2 Sun Dec 14 17:10:35 2008 Google Inc. * google-perftools: version 1.0rc2 release * Fix compile error on 64-bit systems (casting ptr to int) (csilvers) Thu Dec 11 16:01:32 2008 Google Inc. * google-perftools: version 1.0rc1 release * Replace API for selectively disabling heap-checker in code (sanjay) * Add a pre-mmap hook (daven, adlr) * Add MallocExtension interface to set memory-releasing rate (fikes) * Augment pprof to allow any string ending in /pprof/profile (csilvers) * PORTING: Rewrite -- and fix -- malloc patching for windows (dvitek) * PORTING: Add nm-pdb and addr2line-pdb for use by pprof (dvitek) * PORTING: Improve cygwin and mingw support (jperkins, csilvers) * PORTING: Fix pprof for mac os x, other pprof improvements (csilvers) * PORTING: Fix some PPC bugs in our locking code (anton.blanchard) * A new unittest, smapling_test, to verify tcmalloc-profiles (csilvers) * Turn off TLS for gcc < 4.1.2, due to a TLS + -fPIC bug (csilvers) * Prefer __builtin_frame_address to assembly for stacktraces (nlewycky) * Separate tcmalloc.cc out into multiple files -- finally! (kash) * Make our locking code work with -fPIC on 32-bit x86 (aruns) * Fix an initialization-ordering bug for tcmalloc/profiling (csilvers) * Use "initial exec" model of TLS to speed up tcmalloc (csilvers) * Enforce 16-byte alignment for tcmalloc, for SSE (sanjay) Tue Sep 23 08:56:31 2008 Google Inc. * google-perftools: version 0.99.2 release * COMPILE FIX: add #include needed for FreeBSD and OS X (csilvers) Sat Sep 20 09:37:18 2008 Google Inc. * google-perftools: version 0.99.1 release * BUG FIX: look for nm, etc in /usr/bin, not /usr/crosstool (csilvers) Thu Sep 18 16:00:27 2008 Google Inc. * google-perftools: version 0.99 release * Add IsHeapProfileRunning (csilvers) * Add C shims for some of the C++ header files (csilvers) * Fix heap profile file clean-up logic (maxim) * Rename linuxthreads.c to .cc for better compiler support (csilvers) * Add source info to disassembly in pprof (sanjay) * Use open instead of fopen to avoid memory alloc (csilvers) * Disable malloc extensions when running under valgrind (kcc) * BUG FIX: Fix out-of-bound error by reordering a check (larryz) * Add Options struct to ProfileData (cgd) * Correct PC-handling of --base in pprof (csilvers) * Handle 1 function occurring twice in an image (sanjay) * Improve stack-data cleaning (maxim) * Use 'struct Foo' to make header C compatible (csilvers) * Add 'total' line to pprof --text (csilvers) * Pre-allocate buffer for heap-profiler to avoid OOM errors (csilvers) * Allow a few more env-settings to control tcmalloc (csilvers) * Document some of the issues involving thread-local storage (csilvers) * BUG FIX: Define strtoll and friends for windows (csilvers) Mon Jun 9 16:47:03 2008 Google Inc. * google-perftools: version 0.98 release * Add ProfilerStartWithOptions() (cgd) * Change tcmalloc_minimal to not do any stack-tracing at all (csilvers) * Prefer mmap to sbrk for 64-buit debug mode (sanjay) * Fix accounting for some tcmalloc stats (sanjay) * Use setrlimit() to keep unittests from killing the machine (odo) * Fix a bug when sbrk-ing near address 4G (csilvers) * Make MallocHook thread-safe (jyasskin) * Fix windows build for MemoryBarrier (jyasskin) * Fix CPU-profiler docs to mention correct libs (csilvers) * Fix for GetHeapProfile() when heap-profiling is off (maxim) * Avoid realloc resizing ping-pongs using hysteresis (csilvers) * Add --callgrind output support to pprof (klimek) * Fix profiler.h and heap-profiler.h to be C-compatible (csilvers) * Break malloc_hook.h into two parts to reduce dependencies (csilvers) * Better handle systems that don't implement mmap (csilvers) * PORTING: disable system_alloc_unittest for msvc (csilvers) * PORTING: Makefile tweaks to build better on cygwin (csilvers) Mon Apr 21 15:20:52 2008 Google Inc. * google-perftools: version 0.97 release * Refactor GetHeapProfile to avoid using malloc (maxim) * Fix heap-checker and heap-profiler hook interactions (maxim) * Fix a data race in MemoryRegionMap::Lock (jyasskin) * Improve thread-safety of leak checker (maxim) * Fix mmap profile to no longer deadlock (maxim) * Fix rpm to have devel package depend on non-devel (csilvers) * PORTING: Fix clock-speed detection for Mac OS X (csilvers) Tue Mar 18 14:30:44 2008 Google Inc. * google-perftools: version 0.96 release * major atomicops rewrite; fixed atomic ops code for linux/ppc (vchen) * nix the stacktrace library; now build structure is simpler (csilvers) * Speed up heap-checker, and reduce extraneous logging (maxim) * Improve itimer code for NPTL case (cgd) * Add source code annotations for use by valgrind, etc (kcc) * PORTING: Fix high resolution timers for Mac OS X (adlr) Tue Feb 19 12:01:31 2008 Google Inc. * google-perftools: version 0.95.1 release (bugfix release) * x86_64 compile-fix: nix pread64 and pwrite64 (csilvers) * more heap-checker debug logging (maxim) * minor improvement to x86_64 CycleClock (gpike) Tue Feb 12 12:28:32 2008 Google Inc. * google-perftools: version 0.95 release * Better -- not perfect -- support for linux-ppc (csilvers) * Fix race condition in libunwind stacktrace (aruns) * Speed up x86 spinlock locking (m3b) * Improve heap-checker performance (maxim) * Heap checker traverses more ptrs inside heap-alloced objects (maxim) * Remove deprecated ProfilerThreadState function (cgd) * Update libunwind documentation for statically linked binaries (aruns) Mon Dec 3 23:51:54 2007 Google Inc. * google-perftools: version 0.94.1 release (bugfix release) * Fix missing #includes for x86_64 compile using libunwind (csilvers) Thu Nov 29 07:59:43 2007 Google Inc. * google-perftools: version 0.94 release * PORTING: MinGW/Msys support -- runs same code as MSVC does (csilvers) * PORTING: Add NumCPUs support for Mac OS X (csilvers) * Work around a sscanf bug in glibc(?) (waldemar) * Fix Windows MSVC bug triggered by thread deletion (csilvers) * Fix bug that triggers in MSVC /O2: missing volatile (gpike) * March-of-time support: quiet warnings/errors for gcc 4.2, OS X 10.5 * Modify pprof so it works without nm: useful for windows (csilvers) * pprof: Support filtering for CPU profiles (cgd) * Bugfix: have realloc report to hooks in all situations (maxim) * Speed improvement: replace slow memcpy with std::copy (soren) * Speed: better iterator efficiency in RecordRegionRemoval (soren) * Speed: minor speed improvements via better bitfield alignment (gpike) * Documentation: add documentation of binary profile output (cgd) Fri Aug 17 12:32:56 2007 Google Inc. * google-perftools: version 0.93 release * PORTING: everything compiles on Solaris, OS X, FreeBSD (see INSTALL) * PORTING: cpu-profiler works on most platforms (much better GetPC()) * PORTING: heap-profiler works on most platforms * PORTING: improved windows support, including release builds * No longer build or run ptmalloc tests by default * Add support for using memfs filesystem to allocate memory in linux * WINDOWS: give debug library and release library different names Tue Jul 17 22:26:27 2007 Google Inc. * google-perftools: version 0.92 release * PERFORMANCE: use a packed cache to speed up tcmalloc * PORTING: preliminary windows support! (see README.windows) * PORTING: better support for solaris, OS X, FreeBSD (see INSTALL) * Envvar support for running the heap-checker under gdb * Add weak declarations to maybe_threads to fix no-pthreads compile bugs * Some 64bit fixes, especially with pprof * Better heap-checker support for some low-level allocations * Fix bug where heap-profiles would sometimes get truncated * New documentation about how to handle common heap leak situations * Use computed includes for hash_map/set: easier config * Added all used .m4 templates to the distribution Wed Apr 18 16:43:55 2007 Google Inc. * google-perftools: version 0.91 release * Brown-paper-bag bugfix: compilation error on some x86-64 machines Fri Apr 13 14:50:51 2007 Google Inc. * google-perftools: version 0.90 release * (As the version-number jump hints, this is a major new release: almost every piece of functionality was rewritten. I can't do justice to all the changes, but will concentrate on highlights.) *** USER-VISIBLE CHANGES: * Ability to "release" unused memory added to tcmalloc * Exposed more tweaking knobs via environment variables (see docs) * pprof tries harder to map addresses to functions * tcmalloc_minimal compiles and runs on FreeBSD 6.0 and Solaris 10 *** INTERNAL CHANGES: * Much better 64-bit support * Better multiple-processor support (e.g. multicore contention tweaks) * Support for recent kernel ABI changes (e.g. new arg to mremap) * Addition of spinlocks to tcmalloc to reduce contention cost * Speed up tcmalloc by using __thread on systems that support TLS * Total redesign of heap-checker to improve liveness checking * More portable stack-frame analysis -- no more hard-coded constants! * Disentangled heap-profiler code and heap-checker code * Several new unittests to test, e.g., thread-contention costs * Lots of small (but important!) bug fixes: e.g., fixing GetPC on amd64 *** KNOWN PROBLEMS: * CPU-profiling may crash on x86_64 (64-bit) systems. See the README * Profiling/heap-checking may deadlock on x86_64 systems. See README Wed Jun 14 15:11:14 2006 Google Inc. * google-perftools: version 0.8 release * Experimental support for remote profiling added to pprof (many) * Fixed race condition in ProfileData::FlushTable (etune) * Better support for weird /proc maps (maxim, mec) * Fix heap-checker interaction with gdb (markus) * Better 64-bit support in pprof (aruns) * Reduce scavenging cost in tcmalloc by capping NumMoveSize (sanjay) * Cast syscall(SYS_mmap); works on more 64-bit systems now (menage) * Document the text output of pprof! (csilvers) * Better compiler support for no-THREADS and for old compilers (csilvers) * Make libunwind the default stack unwinder for x86-64 (aruns) * Somehow the COPYING file got erased. Regenerate it (csilvers) Thu Apr 13 20:59:09 2006 Google Inc. * google-perftools: version 0.7 release * Major rewrite of thread introspection for new kernels (markus) * Major rewrite of heap-checker to use new thread tools (maxim) * Add proper support for following data in thread registers (maxim) * Syscall support for older kernels, including _syscall6 (markus) * Support PIC mode (markus, mbland, iant) * Better support for running in non-threaded contexts (csilvers) Fri Jan 27 14:04:27 2006 Google Inc. * google-perftools: version 0.6 release * More sophisticated stacktrace usage, possibly using libunwind (aruns) * Update pprof to handle 64-bit profiles (dehnert) * Fix GetStackTrace to correctly return top stackframe (sanjay) * Add ANSI compliance for new and new[], including new_handler (jkearney) * More accuracy by reading ELF files directly rather than objdump (mec) * Add readline support for pprof (addi) * Add #includes for PPC (csilvers) * New PC-detection routine for ibook powerpc (asbestoshead) * Vastly improved tcmalloc unittest (csilvers) * Move documentation from /usr/doc to /usr/share/doc Mon Nov 14 17:28:59 2005 Google Inc. * google-perftools: version 0.5 release * Add va_start/va_end calls around vsnprintf() (csilvers) * Write our own __syscall_return(), since it's not defined consistently on all 64-bit linux distros (markus) Wed Oct 26 15:19:16 2005 Google Inc. * google-perftools: version 0.4 release * Decrease fragmentation in tcmalloc (lefevere) * Support for ARM in some of the thread-specific code (markus) * Turn off heap-checker for statically-linked binaries, which cause error leak reports now (etune) * Many pprof improvements, including a command-line interface (jeff) * CPU profiling now automatically affects all threads in linux 2.6. (Kernel bugs break CPU profiling and threads in linux 2.4 a bit.) ProfilerEnable() and ProfilerDisable() are deprecated. (sanjay) * tcmalloc now correctly intercepts memalign (m3b, maxim) * Syntax fix: added missing va_end()s. Helps non-gcc compiling (etune) * Fixed a few coredumper bugs: race condition after PTRACE_DETACH, ignore non-aligned stackframe pointers (markus, menage) * 64-bit cleanup, especially for spinlock code (etune) and mmap (sanjay) * Better support for finding threads in linux (markus) * tcmalloc now tracks those stack traces that allocate memory (sanjay) * Work around a weird setspecific problem (sanjay) * Fix tcmalloc overflow problems when an alloc is close to 2G/4G (sanjay) Fri Jun 24 18:02:26 2005 Google Inc. * google-perftools: version 0.3 release * Add missing errno include for one of the unittests (csilvers) * Reduce tcmalloc startup memory from 5M to 256K (sanjay) * Add support for mallopt() and mallinfo (sanjay) * Improve stacktrace's performance on some 64-bit systems (etune) * Improve the stacktrace unittest (etune) Tue May 31 08:14:38 2005 Google Inc. * google-perftools: version 0.2 release * Use mmap2() instead of mmap(), to map more memory (menage) * Do correct pthread-local checking in heap-checker! (maxim) * Avoid overflow on 64-bit machines in pprof (sanjay) * Add a few more GetPC() functions, including for AMD (csilvers) * Better method for overriding pthread functions (menage) * (Hacky) fix to avoid overwriting profile files after fork() (csilvers) * Crashing bugfix involving dumping heaps on small-stack threads (tudor) * Allow library versions with letters at the end (csilvers) * Config fixes for systems that don't define PATH_MAX (csilvers) * Confix fixes so we no longer need config.h after install (csilvers) * Fix to pprof to correctly read very big cpu profiles (csilvers) * Fix to pprof to deal with new commandline flags in modern gv's * Better error reporting when we can't access /proc/maps (etune) * Get rid of the libc-preallocate code (which could crash on some systems); no longer needed with local-threads fix (csilvers) Tue Feb 8 09:57:17 2005 Google Inc. * google-perftools: initial release: The google-perftools package contains some utilities to improve and analyze the performance of C++ programs. This includes an optimized thread-caching malloc() and cpu and heap profiling utilities. gperftools-gperftools-2.18/INSTALL000066400000000000000000000406611513545575200170660ustar00rootroot00000000000000Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Perftools-Specific Install Notes ================================ See generic autotool-provided installation notes at the end. Immediately below you can see gperftools-specific details. *** Building from source repository As of 2.1 gperftools does not have configure and other autotools products checked into it's source repository. This is common practice for projects using autotools. NOTE: Source releases (.tar.gz that you download from https://github.com/gperftools/gperftools/releases) still have all required files just as before. Nothing has changed w.r.t. building from .tar.gz releases. But, in order to build gperftools checked out from subversion repository you need to have autoconf, automake and libtool installed. And before running ./configure you have to generate it (and a bunch of other files) by running ./autogen.sh script. That script will take care of calling correct autotools programs in correct order. If you're maintainer then it's business as usual too. Just run make dist (or, preferably, make distcheck) and it'll produce .tar.gz or .tar.bz2 with all autotools magic already included. So that users can build our software without having autotools. *** TCMALLOC LARGE PAGES: TRADING TIME FOR SPACE You can set a compiler directive that makes tcmalloc faster, at the cost of using more space (due to internal fragmentation). Internally, tcmalloc divides its memory into "pages." The default page size is chosen to minimize memory use by reducing fragmentation. The cost is that keeping track of these pages can cost tcmalloc time. We've added a new flag to tcmalloc that enables a larger page size. In general, this will increase the memory needs of applications using tcmalloc. However, in many cases it will speed up the applications as well, particularly if they allocate and free a lot of memory. We've seen average speedups of 3-5% on Google applications. To build libtcmalloc with large pages you need to use the --with-tcmalloc-pagesize=ARG configure flag, e.g.: ./configure --with-tcmalloc-pagesize=32 The ARG argument can be 4, 8, 16, 32, 64, 128 or 256 which sets the internal page size to 4K, 8K, 16K, 32K, 64K, 128K and 256K respectively. The default is 8K. *** SMALL TCMALLOC CACHES: TRADING SPACE FOR TIME You can set a compiler directive that makes tcmalloc use less memory for overhead, at the cost of some time. Internally, tcmalloc keeps information about some of its internal data structures in a cache. This speeds memory operations that need to access this internal data. We've added a new, experimental flag to tcmalloc that reduces the size of this cache, decresaing the memory needs of applications using tcmalloc. This feature is still very experimental; it's not even a configure flag yet. To build libtcmalloc with smaller internal caches, run ./configure CXXFLAGS=-DTCMALLOC_SMALL_BUT_SLOW (or add -DTCMALLOC_SMALL_BUT_SLOW to your existing CXXFLAGS argument). *** TCMALLOC AND DLOPEN To improve performance, we use the "initial exec" model of Thread Local Storage in tcmalloc. The price for this is the library will not work correctly if it is loaded via dlopen(). This should not be a problem, since loading a malloc-replacement library via dlopen is asking for trouble in any case: some data will be allocated with one malloc, some with another. *** COMPILING ON NON-LINUX SYSTEMS We regularly build and test on typical modern GNU/Linux systems. You should expect all tests to pass on modern Linux distros and x86, aarch64 and riscv machines. Other machine types may fail some tests, but you should expect at least malloc to be fully functional. Perftools has been tested on the following non-Linux systems: Recent versions of FreeBSD (x86-64 mostly) Recent version of NetBSD (x86-64) Recent versions of OSX (aarch64, x86 and ppc hasn't been tested for some time) Recent OpenSolaris (x86_64) Recent QNX Windows using both MSVC (starting from MSVC 2019 and later) and mingw toolchains Portions of gperftools work on those other systems. The basic memory-allocation library, tcmalloc_minimal, works on all systems. The cpu-profiler also works fairly widely (with notable exception of Windows, of course). However, the heap-profiler is not yet as widely supported. In general, the 'configure' script will detect what OS you are building for, and only build the components that work on that OS. Note that tcmalloc_minimal is perfectly usable as a malloc/new replacement, so it is possible to use tcmalloc on all the systems above, by linking in libtcmalloc_minimal. ** Windows (MSVC and MinGW): Work on Windows is rather preliminary: only tcmalloc_minimal is supported. Note, our code base requires APIs available starting from Windows 8 and later. This Windows functionality is also available using MinGW and Msys, In this case, you can use the regular './configure && make' process. 'make install' should also work. The Makefile will limit itself to those libraries and binaries that work on windows. ** AIX (as of 2021) I've tested using the IBM XL and IBM Open XL Compilers. The minimum requirement for IBM XL is V16 which includes C++11 support. IBM XL and gcc are not ABI compatible. If you would like to use the library with a gcc built executable then the library must also be built with gcc. To use the library with and IBM XL built binary then it follows that the library must also be built with IBM XL. Both 32-bit and 64-bit builds have been tested. To do a 32-bit IBM XL build: % ./configure CC="xlclang" CXX="xlclang++" AR="ar" RANLIB="ranlib" NM="nm" To do a 64-bit IBM XL build: % ./configure CC="xlclang -q64" CXX="xlclang++ -q64" AR="ar -X64" RANLIB="ranlib -X64" NM="nm -X64" Add your favorite optimization levels via CFLAGS and CXXFLAGS. If you link to the shared library but it may not work as you expect. Allocations and deallocations that occur from within the Standard C and C++ libraries will not be redirected the tcmalloc library. The recommended method is to use the AIX User-defined malloc replacement as documented by IBM. This replaces the default AIX memory subsystem with a user defined memory subsystem. The AIX user defined memory subsystem specifies that the 32- and 64- bit objects must be placed in an archive with the 32-bit shared object named mem32.o and the 64-bit shared object named mem64.o. It is recommended to make combined 32_64 bit archive by doing a 64-bit build, then copy the shared library to mem64.o add mem64.o the archive, then do a 32-bit build copy the shared library to mem32.o and add it to the same combined archive. For eg) perform a 64-bit build then: % cp libtcmalloc_minimal.so.4 mem64.o % ar -X32_64 -r libtmalloc_minimal.a mem64.o Followed by a 32-bit build: % cp libtcmalloc_minimal.so.4 mem32.o % ar -X32_64 -r libtmalloc_minimal.a mem32.o The final archive should contain both mem32.o and mem64.o To use the library you are expected have the library location in your LIBPATH or LD_LIBRARY_PATH followed by exporting the environment variable MALLOCTYPE=user:libtcmalloc_minimal.a to enable the new user defined memory subsystem. I recommend using: % MALLOCTYPE=user:libtcmalloc_minimal.a to minimize the impact of replacing the memory subsystem. Once the subsystem is replaced it is used for all commands issued from the terminal. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. gperftools-gperftools-2.18/MODULE.bazel000066400000000000000000000004761513545575200200410ustar00rootroot00000000000000module( name = "gperftools", version = "2.18", compatibility_level = 2, ) bazel_dep(name = "bazel_skylib", version = "1.9.0") bazel_dep(name = "platforms", version = "1.0.0") bazel_dep(name = "rules_cc", version = "0.2.16") bazel_dep(name = "googletest", version = "1.17.0.bcr.2", dev_dependency = True) gperftools-gperftools-2.18/Makefile.am000066400000000000000000001105241513545575200200650ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in # Note: for every library we create, we're explicit about what symbols # we export. In order to avoid complications with C++ mangling, we always # use the regexp for of specifying symbols. # Make sure that when we re-make ./configure, we get the macros we need ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = subdir-objects # This is so we can #include AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src if !WITH_STACK_TRACE AM_CPPFLAGS += -DNO_TCMALLOC_SAMPLES endif !WITH_STACK_TRACE # This is mostly based on configure options AM_CXXFLAGS = $(PTHREAD_CFLAGS) # These are good warnings to turn on by default. if GCC AM_CXXFLAGS += -Wall -Wwrite-strings -Woverloaded-virtual \ -Wno-sign-compare endif GCC if HAVE_SIZED_DEALLOCATION AM_CXXFLAGS += -fsized-deallocation endif HAVE_SIZED_DEALLOCATION if ENABLE_W_THREAD_SAFETY AM_CXXFLAGS += -Wthread-safety endif ENABLE_W_THREAD_SAFETY # The -no-undefined flag allows libtool to generate shared libraries for # Cygwin and MinGW. AM_LDFLAGS = -no-undefined $(NANOSLEEP_LIBS) $(PTHREAD_LIBS) # respect --enable-frame-pointers regardless of architecture if ENABLE_FRAME_POINTERS AM_CXXFLAGS += -fno-omit-frame-pointer -DFORCED_FRAME_POINTERS else !ENABLE_FRAME_POINTERS if ENABLE_FP_FLAGS AM_CXXFLAGS += -fno-omit-frame-pointer -momit-leaf-frame-pointer endif ENABLE_FP_FLAGS endif !ENABLE_FRAME_POINTERS # For windows systems (at least, mingw), we need to tell all our # tests to link in libtcmalloc using -u. This is because libtcmalloc # accomplishes its tasks via patching, leaving no work for the linker # to identify, so the linker will ignore libtcmalloc by default unless # we explicitly create a dependency via -u. if MINGW TCMALLOC_FLAGS = -Wl,-u__tcmalloc else TCMALLOC_FLAGS = endif !MINGW perftoolsincludedir = $(includedir)/gperftools # The .h files you want to install (that is, .h files that people # who install this package can include in their own applications.) # We'll add to this later, on a library-by-library basis perftoolsinclude_HEADERS = src/gperftools/tcmalloc.h # This is for HTML and other documentation you want to install. Add # your documentation files (in doc/) in addition to these top-level # boilerplate files. We'll add to this later, on a library-by-library # basis dist_doc_DATA = AUTHORS COPYING INSTALL NEWS README README_windows.txt \ ChangeLog.old # The libraries (.so's) you want to install # We'll add to this later, on a library-by-library basis lib_LTLIBRARIES = # This is for 'convenience libraries' -- basically just a container for sources noinst_LTLIBRARIES = # unittests you want to run when people type 'make check'. # Note: tests cannot take any arguments! TESTS = # TESTS_ENVIRONMENT sets environment variables for when you run unittest. # We always get "srcdir" set for free. # We'll add to this later, on a library-by-library basis. TESTS_ENVIRONMENT = # All script tests should be added here noinst_SCRIPTS = # If your test calls another program that, like the test itself, shouldn't # be installed, add it here. (Stuff in TESTS is automatically added later). noinst_PROGRAMS = # Binaries we might build that should be installed bin_PROGRAMS = # This is my own var, used for extra libraries I make that I need installed EXTRA_INSTALL = ## vvvv RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS ### ------- various support library routines # Having set of common helpers helps with unit testing various "guts" noinst_LTLIBRARIES += libcommon.la libcommon_la_SOURCES = src/base/logging.cc \ src/base/generic_writer.cc \ src/base/sysinfo.cc \ src/base/proc_maps_iterator.cc \ src/base/dynamic_annotations.cc \ src/base/spinlock.cc \ src/base/spinlock_internal.cc noinst_LTLIBRARIES += liblow_level_alloc.la liblow_level_alloc_la_SOURCES = src/base/low_level_alloc.cc if MINGW libcommon_la_SOURCES += src/windows/port.cc \ src/windows/ia32_modrm_map.cc \ src/windows/ia32_opcode_map.cc \ src/windows/mini_disassembler.cc \ src/windows/preamble_patcher.cc \ src/windows/preamble_patcher_with_stub.cc # windows bits need some extra libraries AM_LDFLAGS += -lpsapi -lsynchronization -lshlwapi # patch_functions.cc #includes tcmalloc.cc, so no need to link it in. TCMALLOC_CC = src/windows/patch_functions.cc SYSTEM_ALLOC_CC = src/windows/system-alloc.cc else !MINGW TCMALLOC_CC = src/tcmalloc.cc SYSTEM_ALLOC_CC = src/system-alloc.cc endif !MINGW # On MSVC, we need couple more tests. WINDOWS_EXTRA = src/windows/preamble_patcher_test.cc \ src/windows/shortproc.asm \ src/windows/auto_testing_hook.h ### Unittests noinst_LTLIBRARIES += libgtest.la libgtest_la_SOURCES = vendor/googletest/googletest/src/gtest_main.cc \ vendor/googletest/googletest/src/gtest-assertion-result.cc \ vendor/googletest/googletest/src/gtest-death-test.cc \ vendor/googletest/googletest/src/gtest-filepath.cc \ vendor/googletest/googletest/src/gtest-matchers.cc \ vendor/googletest/googletest/src/gtest-port.cc \ vendor/googletest/googletest/src/gtest-printers.cc \ vendor/googletest/googletest/src/gtest-test-part.cc \ vendor/googletest/googletest/src/gtest-typed-test.cc \ vendor/googletest/googletest/src/gtest.cc libgtest_la_CPPFLAGS = -I$(top_srcdir)/vendor/googletest/googletest/include \ -I$(top_srcdir)/vendor/googletest/googletest/ $(AM_CPPFLAGS) libgtest_la_LIBADD = $(REGEX_LIBS) gtest_CPPFLAGS = -I$(top_srcdir)/vendor/googletest/googletest/include $(AM_CPPFLAGS) # Note, we skip this test on mingw (and windows in general). It uses # unsetenv, which is not available on win32. if !MINGW TESTS += unique_path_unittest unique_path_unittest_SOURCES = src/tests/unique_path_unittest.cc unique_path_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(AM_LDFLAGS) unique_path_unittest_CPPFLAGS = $(gtest_CPPFLAGS) unique_path_unittest_LDADD = libcommon.la libgtest.la endif !MINGW TESTS += generic_writer_test generic_writer_test_SOURCES = src/tests/generic_writer_test.cc generic_writer_test_CPPFLAGS = $(gtest_CPPFLAGS) generic_writer_test_LDADD = libcommon.la libgtest.la TESTS += proc_maps_iterator_test proc_maps_iterator_test_SOURCES = src/tests/proc_maps_iterator_test.cc proc_maps_iterator_test_CPPFLAGS = $(gtest_CPPFLAGS) proc_maps_iterator_test_LDADD = libcommon.la libgtest.la TESTS += for_each_line_test for_each_line_test_SOURCES = src/tests/for_each_line_test.cc for_each_line_test_CPPFLAGS = $(gtest_CPPFLAGS) for_each_line_test_LDADD = libcommon.la libgtest.la if WITH_HEAP_PROFILER_OR_CHECKER TESTS += low_level_alloc_unittest low_level_alloc_unittest_SOURCES = src/tests/low_level_alloc_unittest.cc # By default, MallocHook takes stack traces for use by the heap-checker. # We don't need that functionality here, so we turn it off to reduce deps. low_level_alloc_unittest_CXXFLAGS = -DNO_TCMALLOC_SAMPLES $(AM_CXXFLAGS) low_level_alloc_unittest_CPPFLAGS = $(gtest_CPPFLAGS) low_level_alloc_unittest_LDADD = liblow_level_alloc.la libcommon.la libgtest.la endif WITH_HEAP_PROFILER_OR_CHECKER ### ------- stack trace if WITH_STACK_TRACE ### The header files we use. We divide into categories based on directory perftoolsinclude_HEADERS += src/gperftools/stacktrace.h ### Making the library noinst_LTLIBRARIES += libstacktrace.la libstacktrace_la_SOURCES = src/stacktrace.cc \ src/base/elf_mem_image.cc \ src/base/vdso_support.cc libstacktrace_la_LIBADD = $(UNWIND_LIBS) ### Unittests TESTS += stacktrace_unittest stacktrace_unittest_SOURCES = src/tests/stacktrace_unittest.cc \ $(libstacktrace_la_SOURCES) stacktrace_unittest_CXXFLAGS = $(AM_CXXFLAGS) -DSTACKTRACE_IS_TESTED stacktrace_unittest_LDADD = $(libstacktrace_la_LIBADD) $(STACKTRACE_UNITTEST_LIBS) libcommon.la # nice to have. Allows glibc's backtrace_symbols to work. stacktrace_unittest_LDFLAGS = -export-dynamic TESTS += check_address_test check_address_test_SOURCES = src/tests/check_address_test.cc check_address_test_CPPFLAGS = $(gtest_CPPFLAGS) check_address_test_LDADD = libcommon.la libgtest.la endif WITH_STACK_TRACE ### ------- tcmalloc_minimal (thread-caching malloc) perftoolsinclude_HEADERS += src/gperftools/malloc_hook.h \ src/gperftools/malloc_hook_c.h \ src/gperftools/malloc_extension.h \ src/gperftools/malloc_extension_c.h \ src/gperftools/nallocx.h ### Making the library MINIMAL_MALLOC_SRC = src/common.cc \ src/internal_logging.cc \ $(SYSTEM_ALLOC_CC) \ src/memfs_malloc.cc \ src/safe_strerror.cc \ src/central_freelist.cc \ src/page_heap.cc \ src/sampler.cc \ src/span.cc \ src/stack_trace_table.cc \ src/static_vars.cc \ src/thread_cache.cc \ src/thread_cache_ptr.cc \ src/malloc_hook.cc \ src/malloc_extension.cc lib_LTLIBRARIES += libtcmalloc_minimal.la libtcmalloc_minimal_la_SOURCES = $(TCMALLOC_CC) $(MINIMAL_MALLOC_SRC) libtcmalloc_minimal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \ -DNDEBUG $(AM_CXXFLAGS) # -version-info gets passed to libtool libtcmalloc_minimal_la_LDFLAGS = -version-info @TCMALLOC_SO_VERSION@ $(AM_LDFLAGS) libtcmalloc_minimal_la_LIBADD = libcommon.la ### ------- unit tests for various internal modules of tcmalloc TESTS += addressmap_unittest addressmap_unittest_SOURCES = src/tests/addressmap_unittest.cc addressmap_unittest_CPPFLAGS = $(gtest_CPPFLAGS) addressmap_unittest_LDADD = libcommon.la libgtest.la TESTS += packed_cache_test packed_cache_test_SOURCES = src/tests/packed-cache_test.cc src/internal_logging.cc packed_cache_test_CPPFLAGS = $(gtest_CPPFLAGS) packed_cache_test_LDADD = libcommon.la libgtest.la TESTS += safe_strerror_test safe_strerror_test_SOURCES = src/tests/safe_strerror_test.cc \ src/safe_strerror.cc safe_strerror_test_CPPFLAGS = $(gtest_CPPFLAGS) safe_strerror_test_LDADD = libcommon.la libgtest.la TESTS += cleanup_test cleanup_test_SOURCES = src/tests/cleanup_test.cc cleanup_test_CPPFLAGS = $(gtest_CPPFLAGS) cleanup_test_LDADD = libgtest.la TESTS += function_ref_test function_ref_test_SOURCES = src/tests/function_ref_test.cc function_ref_test_CPPFLAGS = $(gtest_CPPFLAGS) function_ref_test_LDADD = libgtest.la TESTS += trivialre_test trivialre_test_SOURCES = benchmark/trivialre_test.cc trivialre_test_CPPFLAGS = $(gtest_CPPFLAGS) trivialre_test_LDADD = libgtest.la TESTS += pagemap_unittest pagemap_unittest_SOURCES = src/tests/pagemap_unittest.cc \ src/internal_logging.cc pagemap_unittest_CPPFLAGS = $(gtest_CPPFLAGS) pagemap_unittest_LDADD = libcommon.la libgtest.la # note, it is not so great that page heap testing requires bringing # almost entirety of tcmalloc (short of tcmalloc.cc), but it is what # we have. TESTS += page_heap_test page_heap_test_SOURCES = src/tests/page_heap_test.cc \ $(libtcmalloc_minimal_la_SOURCES) page_heap_test_CXXFLAGS = -DNO_TCMALLOC_SAMPLES $(AM_CXXFLAGS) page_heap_test_CPPFLAGS = $(gtest_CPPFLAGS) page_heap_test_LDADD = libcommon.la libgtest.la # note, it is not so great that stack_trace_table testing requires # bringing almost entirety of tcmalloc (short of tcmalloc.cc), but it # is what we have. TESTS += stack_trace_table_test stack_trace_table_test_SOURCES = src/tests/stack_trace_table_test.cc \ src/stack_trace_table.cc src/internal_logging.cc stack_trace_table_test_CPPFLAGS = $(gtest_CPPFLAGS) stack_trace_table_test_CXXFLAGS = -DSTACK_TRACE_TABLE_IS_TESTED $(AM_CXXFLAGS) stack_trace_table_test_LDADD = libcommon.la libgtest.la TESTS += malloc_hook_test malloc_hook_test_SOURCES = src/tests/malloc_hook_test.cc \ src/tests/testutil.cc \ src/malloc_hook.cc malloc_hook_test_CXXFLAGS = -DNO_TCMALLOC_SAMPLES $(AM_CXXFLAGS) malloc_hook_test_CPPFLAGS = $(gtest_CPPFLAGS) malloc_hook_test_LDADD = libcommon.la libgtest.la TESTS += sampler_test sampler_test_SOURCES = src/tests/sampler_test.cc \ src/sampler.cc sampler_test_CPPFLAGS = $(gtest_CPPFLAGS) sampler_test_LDADD = libcommon.la libgtest.la ### Unittests for libtcmalloc_minimal.la TESTS += tcmalloc_minimal_unittest tcmalloc_minimal_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ src/tests/testutil.cc tcmalloc_minimal_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) tcmalloc_minimal_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcmalloc_minimal_unittest_LDADD = libtcmalloc_minimal.la libgtest.la # lets make sure we exerice ASSERTs in at least in statically linked # configuration TESTS += tcm_min_asserts_unittest tcm_min_asserts_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ src/tests/testutil.cc \ $(libtcmalloc_minimal_la_SOURCES) tcm_min_asserts_unittest_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \ $(AM_CXXFLAGS) tcm_min_asserts_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcm_min_asserts_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) tcm_min_asserts_unittest_LDADD = libcommon.la libgtest.la TESTS += tcmalloc_minimal_large_unittest tcmalloc_minimal_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc tcmalloc_minimal_large_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) tcmalloc_minimal_large_unittest_LDADD = libtcmalloc_minimal.la TESTS += tcmalloc_minimal_large_heap_fragmentation_unittest tcmalloc_minimal_large_heap_fragmentation_unittest_SOURCES = src/tests/large_heap_fragmentation_unittest.cc tcmalloc_minimal_large_heap_fragmentation_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) tcmalloc_minimal_large_heap_fragmentation_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcmalloc_minimal_large_heap_fragmentation_unittest_LDADD = libtcmalloc_minimal.la libgtest.la if !MINGW TESTS += system_alloc_unittest system_alloc_unittest_SOURCES = src/tests/system-alloc_unittest.cc system_alloc_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) system_alloc_unittest_CPPFLAGS = $(gtest_CPPFLAGS) system_alloc_unittest_LDADD = libtcmalloc_minimal.la libgtest.la endif !MINGW TESTS += frag_unittest frag_unittest_SOURCES = src/tests/frag_unittest.cc frag_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) frag_unittest_CPPFLAGS = $(gtest_CPPFLAGS) frag_unittest_LDADD = libtcmalloc_minimal.la libgtest.la TESTS += markidle_unittest markidle_unittest_SOURCES = src/tests/markidle_unittest.cc markidle_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) markidle_unittest_CPPFLAGS = $(gtest_CPPFLAGS) markidle_unittest_LDADD = libtcmalloc_minimal.la libgtest.la TESTS += current_allocated_bytes_test current_allocated_bytes_test_SOURCES = src/tests/current_allocated_bytes_test.cc current_allocated_bytes_test_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) current_allocated_bytes_test_CPPFLAGS = $(gtest_CPPFLAGS) current_allocated_bytes_test_LDADD = libtcmalloc_minimal.la libgtest.la TESTS += malloc_extension_test malloc_extension_test_SOURCES = src/tests/malloc_extension_test.cc malloc_extension_test_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) malloc_extension_test_CPPFLAGS = $(gtest_CPPFLAGS) malloc_extension_test_LDADD = libtcmalloc_minimal.la libgtest.la TESTS += malloc_extension_c_test malloc_extension_c_test_SOURCES = src/tests/malloc_extension_c_test.cc malloc_extension_c_test_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) malloc_extension_c_test_CPPFLAGS = $(gtest_CPPFLAGS) malloc_extension_c_test_LDADD = libtcmalloc_minimal.la libgtest.la if !MINGW if !OSX TESTS += memalign_unittest memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \ src/tests/testutil.cc memalign_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) memalign_unittest_CPPFLAGS = $(gtest_CPPFLAGS) memalign_unittest_LDADD = libtcmalloc_minimal.la libgtest.la endif !OSX endif !MINGW TESTS += realloc_unittest realloc_unittest_SOURCES = src/tests/realloc_unittest.cc realloc_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) realloc_unittest_CPPFLAGS = $(gtest_CPPFLAGS) realloc_unittest_LDADD = libtcmalloc_minimal.la libgtest.la TESTS += thread_dealloc_unittest thread_dealloc_unittest_SOURCES = src/tests/thread_dealloc_unittest.cc \ src/tests/testutil.cc thread_dealloc_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) thread_dealloc_unittest_LDADD = libtcmalloc_minimal.la TESTS += min_per_thread_cache_size_test min_per_thread_cache_size_test_SOURCES = src/tests/min_per_thread_cache_size_test.cc min_per_thread_cache_size_test_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) min_per_thread_cache_size_test_CPPFLAGS = $(gtest_CPPFLAGS) min_per_thread_cache_size_test_LDADD = libtcmalloc_minimal.la libgtest.la ### Documentation dist_doc_DATA += $(top_srcdir)/docs/*adoc $(top_srcdir)/docs/*gif $(top_srcdir)/docs/*png $(top_srcdir)/docs/dots/*dot gperftools_HTMLDOCS = docs/tcmalloc.html docs/heapprofile.html \ docs/cpuprofile.html docs/cpuprofile-fileformat.html \ docs/pprof_integration.html if !MISSING_ASCIIDOCTOR doc_DATA = $(gperftools_HTMLDOCS) MOSTLYCLEANFILES = $(gperftools_HTMLDOCS) .adoc.html: $(ASCIIDOCTOR) $(ASCIIDOCTOR_FLAGS) -o $@ $< endif !MISSING_ASCIIDOCTOR ### ------- tcmalloc_minimal_debug (thread-caching malloc with debugallocation) if WITH_DEBUGALLOC noinst_LTLIBRARIES += libbacktrace.la libbacktrace_la_SOURCES = vendor/libbacktrace-integration/file-format.c \ vendor/libbacktrace/dwarf.c \ vendor/libbacktrace/fileline.c \ vendor/libbacktrace/posix.c \ vendor/libbacktrace/sort.c \ vendor/libbacktrace/state.c \ vendor/libbacktrace/read.c # note, we're not including our "usual" project-wide AM_CPPFLAGS here libbacktrace_la_CPPFLAGS = -I$(top_srcdir)/vendor/libbacktrace-integration \ -I$(top_srcdir)/vendor/libbacktrace noinst_LTLIBRARIES += libsymbolize.la libsymbolize_la_SOURCES = src/symbolize.cc vendor/libbacktrace-integration/backtrace-alloc.cc libsymbolize_la_LIBADD = libbacktrace.la lib_LTLIBRARIES += libtcmalloc_minimal_debug.la libtcmalloc_minimal_debug_la_SOURCES = src/debugallocation.cc \ $(MINIMAL_MALLOC_SRC) libtcmalloc_minimal_debug_la_CXXFLAGS = $(libtcmalloc_minimal_la_CXXFLAGS) libtcmalloc_minimal_debug_la_LDFLAGS = $(libtcmalloc_minimal_la_LDFLAGS) libtcmalloc_minimal_debug_la_LIBADD = libsymbolize.la liblow_level_alloc.la $(libtcmalloc_minimal_la_LIBADD) ### Unittests TESTS += tcmalloc_minimal_debug_unittest tcmalloc_minimal_debug_unittest_SOURCES = $(tcmalloc_minimal_unittest_SOURCES) tcmalloc_minimal_debug_unittest_LDFLAGS = $(tcmalloc_minimal_unittest_LDFLAGS) tcmalloc_minimal_debug_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcmalloc_minimal_debug_unittest_LDADD = libtcmalloc_minimal_debug.la libgtest.la TESTS += malloc_extension_debug_test malloc_extension_debug_test_SOURCES = $(malloc_extension_test_SOURCES) malloc_extension_debug_test_CXXFLAGS = $(malloc_extension_test_CXXFLAGS) malloc_extension_debug_test_LDFLAGS = $(malloc_extension_test_LDFLAGS) malloc_extension_debug_test_CPPFLAGS = $(gtest_CPPFLAGS) malloc_extension_debug_test_LDADD = libtcmalloc_minimal_debug.la libgtest.la if !MINGW if !OSX TESTS += memalign_debug_unittest memalign_debug_unittest_SOURCES = $(memalign_unittest_SOURCES) memalign_debug_unittest_CXXFLAGS = $(memalign_unittest_CXXFLAGS) memalign_debug_unittest_LDFLAGS = $(memalign_unittest_LDFLAGS) memalign_debug_unittest_CPPFLAGS = $(gtest_CPPFLAGS) memalign_debug_unittest_LDADD = libtcmalloc_minimal_debug.la libgtest.la endif !OSX endif !MINGW TESTS += realloc_debug_unittest realloc_debug_unittest_SOURCES = $(realloc_unittest_SOURCES) realloc_debug_unittest_CXXFLAGS = $(realloc_unittest_CXXFLAGS) realloc_debug_unittest_LDFLAGS = $(realloc_unittest_LDFLAGS) realloc_debug_unittest_CPPFLAGS = $(gtest_CPPFLAGS) realloc_debug_unittest_LDADD = libtcmalloc_minimal_debug.la libgtest.la # debugallocation_test checks that we print a proper stacktrace when # debug-allocs fail, so we can't run it if we don't have stacktrace info. if WITH_STACK_TRACE TESTS += debugallocation_test debugallocation_test_SOURCES = src/tests/debugallocation_test.cc debugallocation_test_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) debugallocation_test_CPPFLAGS = $(gtest_CPPFLAGS) debugallocation_test_LDADD = libtcmalloc_debug.la libgtest.la endif WITH_STACK_TRACE endif WITH_DEBUGALLOC noinst_LTLIBRARIES += librun_benchmark.la librun_benchmark_la_SOURCES = \ benchmark/run_benchmark.cc noinst_PROGRAMS += malloc_bench malloc_bench_shared \ binary_trees binary_trees_shared malloc_bench_SOURCES = benchmark/malloc_bench.cc malloc_bench_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) if ENABLE_STATIC malloc_bench_LDFLAGS += -static endif ENABLE_STATIC malloc_bench_LDADD = librun_benchmark.la libtcmalloc_minimal.la malloc_bench_shared_SOURCES = benchmark/malloc_bench.cc malloc_bench_shared_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) malloc_bench_shared_LDADD = librun_benchmark.la libtcmalloc_minimal.la binary_trees_SOURCES = benchmark/binary_trees.cc binary_trees_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) if ENABLE_STATIC binary_trees_LDFLAGS += -static endif ENABLE_STATIC binary_trees_LDADD = libtcmalloc_minimal.la binary_trees_shared_SOURCES = benchmark/binary_trees.cc binary_trees_shared_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) binary_trees_shared_LDADD = libtcmalloc_minimal.la if !MINGW if WITH_HEAP_PROFILER_OR_CHECKER noinst_PROGRAMS += malloc_bench_shared_full malloc_bench_shared_full_SOURCES = benchmark/malloc_bench.cc malloc_bench_shared_full_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) malloc_bench_shared_full_LDADD = librun_benchmark.la libtcmalloc.la noinst_PROGRAMS += unwind_bench unwind_bench_SOURCES = benchmark/unwind_bench.cc unwind_bench_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) unwind_bench_LDADD = librun_benchmark.la libtcmalloc.la endif WITH_HEAP_PROFILER_OR_CHECKER endif !MINGW ### ------- tcmalloc (thread-caching malloc + heap profiler) if WITH_HEAP_PROFILER_OR_CHECKER perftoolsinclude_HEADERS += src/gperftools/heap-profiler.h \ src/gperftools/heap-checker.h if BUILD_EMERGENCY_MALLOC EMERGENCY_MALLOC_CC = src/emergency_malloc.cc EMERGENCY_MALLOC_DEFINE = -DENABLE_EMERGENCY_MALLOC else !BUILD_EMERGENCY_MALLOC EMERGENCY_MALLOC_CC = EMERGENCY_MALLOC_DEFINE = endif !BUILD_EMERGENCY_MALLOC ### Making the library FULL_MALLOC_SRC = $(MINIMAL_MALLOC_SRC) \ src/heap-profile-table.cc \ src/heap-profiler.cc \ $(EMERGENCY_MALLOC_CC) \ src/malloc_backtrace.cc \ src/heap-checker-stub.cc lib_LTLIBRARIES += libtcmalloc.la libtcmalloc_la_SOURCES = $(TCMALLOC_CC) $(FULL_MALLOC_SRC) libtcmalloc_la_CXXFLAGS = -DNDEBUG $(AM_CXXFLAGS) \ $(EMERGENCY_MALLOC_DEFINE) libtcmalloc_la_LDFLAGS = -version-info @TCMALLOC_SO_VERSION@ $(AM_LDFLAGS) libtcmalloc_la_LIBADD = libstacktrace.la liblow_level_alloc.la libcommon.la ### Unittests TESTS += tcmalloc_unittest tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ src/tests/testutil.cc tcmalloc_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) tcmalloc_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcmalloc_unittest_LDADD = libtcmalloc.la libgtest.la TESTS += tcm_asserts_unittest tcm_asserts_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ src/tests/testutil.cc \ $(libtcmalloc_la_SOURCES) # same cxxflags as libtcmalloc.la but without NDEBUG tcm_asserts_unittest_CXXFLAGS = $(AM_CXXFLAGS) \ $(EMERGENCY_MALLOC_DEFINE) tcm_asserts_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcm_asserts_unittest_LDADD = libstacktrace.la liblow_level_alloc.la libcommon.la libgtest.la # This makes sure it's safe to link in both tcmalloc and # tcmalloc_minimal. (One would never do this on purpose, but perhaps # by accident...) When we can compile libprofiler, we also link it in # to make sure that works too. NOTE: On OS X, it's *not* safe to # link both in (we end up with two copies of every global var, and # the code tends to pick one arbitrarily), so don't run the test there. # (We define these outside the 'if' because they're reused below.) tcmalloc_both_unittest_srcs = src/tests/tcmalloc_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc tcmalloc_both_unittest_lflags = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) tcmalloc_both_unittest_ladd = libtcmalloc.la libtcmalloc_minimal.la libgtest.la if WITH_CPU_PROFILER tcmalloc_both_unittest_ladd += libprofiler.la endif WITH_CPU_PROFILER if !OSX TESTS += tcmalloc_both_unittest tcmalloc_both_unittest_SOURCES = $(tcmalloc_both_unittest_srcs) tcmalloc_both_unittest_LDFLAGS = $(tcmalloc_both_unittest_lflags) tcmalloc_both_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcmalloc_both_unittest_LDADD = $(tcmalloc_both_unittest_ladd) endif !OSX TESTS += tcmalloc_large_unittest tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc tcmalloc_large_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) tcmalloc_large_unittest_LDADD = libtcmalloc.la $(PTHREAD_LIBS) TESTS += tcmalloc_large_heap_fragmentation_unittest tcmalloc_large_heap_fragmentation_unittest_SOURCES = src/tests/large_heap_fragmentation_unittest.cc tcmalloc_large_heap_fragmentation_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) tcmalloc_large_heap_fragmentation_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcmalloc_large_heap_fragmentation_unittest_LDADD = libtcmalloc.la libgtest.la # These unittests often need to run binaries. They're in the current dir TESTS_ENVIRONMENT += BINDIR=. TESTS += heap_checker_stub_test heap_checker_stub_test_SOURCES = src/tests/heap-checker-stub-test.cc heap_checker_stub_test_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) heap_checker_stub_test_LDADD = libtcmalloc.la if !SKIP_PPROF_TESTS TESTS += sampling_test sampling_test_SOURCES = src/tests/sampling_test.cc sampling_test_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) sampling_test_CPPFLAGS = $(gtest_CPPFLAGS) sampling_test_LDADD = libtcmalloc.la $(REGEX_LIBS) endif !SKIP_PPROF_TESTS endif WITH_HEAP_PROFILER_OR_CHECKER if WITH_HEAP_PROFILER if !SKIP_PPROF_TESTS TESTS += heap-profiler_unittest.sh$(EXEEXT) heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh noinst_SCRIPTS += $(heap_profiler_unittest_sh_SOURCES) heap-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \ heap-profiler_unittest rm -f $@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@ # These are sub-programs used by heap-profiler_unittest.sh noinst_PROGRAMS += heap-profiler_unittest heap_profiler_unittest_SOURCES = src/tests/heap-profiler_unittest.cc heap_profiler_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS) heap_profiler_unittest_LDADD = libtcmalloc.la endif !SKIP_PPROF_TESTS endif WITH_HEAP_PROFILER ### ------- tcmalloc with debugallocation if WITH_DEBUGALLOC if WITH_HEAP_PROFILER_OR_CHECKER lib_LTLIBRARIES += libtcmalloc_debug.la libtcmalloc_debug_la_SOURCES = src/debugallocation.cc $(FULL_MALLOC_SRC) libtcmalloc_debug_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) libtcmalloc_debug_la_LDFLAGS = $(libtcmalloc_la_LDFLAGS) libtcmalloc_debug_la_LIBADD = libsymbolize.la $(libtcmalloc_la_LIBADD) ### Unittests TESTS += tcmalloc_debug_unittest tcmalloc_debug_unittest_SOURCES = $(tcmalloc_unittest_SOURCES) tcmalloc_debug_unittest_LDFLAGS = $(tcmalloc_unittest_LDFLAGS) tcmalloc_debug_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcmalloc_debug_unittest_LDADD = libtcmalloc_debug.la libgtest.la if !SKIP_PPROF_TESTS TESTS += sampling_debug_test sampling_debug_test_SOURCES = $(sampling_test_SOURCES) sampling_debug_test_CXXFLAGS = $(sampling_test_CXXFLAGS) sampling_debug_test_CPPFLAGS = $(sampling_test_CPPFLAGS) sampling_debug_test_LDFLAGS = $(sampling_test_LDFLAGS) sampling_debug_test_LDADD = libtcmalloc_debug.la $(REGEX_LIBS) endif !SKIP_PPROF_TESTS endif WITH_HEAP_PROFILER_OR_CHECKER if WITH_HEAP_PROFILER if !SKIP_PPROF_TESTS TESTS += heap-profiler_debug_unittest.sh$(EXEEXT) heap_profiler_debug_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh heap-profiler_debug_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \ heap-profiler_debug_unittest rm -f $@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@ # These are sub-programs used by heap-profiler_debug_unittest.sh noinst_PROGRAMS += heap-profiler_debug_unittest heap_profiler_debug_unittest_SOURCES = $(heap_profiler_unittest_SOURCES) heap_profiler_debug_unittest_CXXFLAGS = $(heap_profiler_unittest_CXXFLAGS) heap_profiler_debug_unittest_LDFLAGS = $(heap_profiler_unittest_LDFLAGS) heap_profiler_debug_unittest_LDADD = libtcmalloc_debug.la endif !SKIP_PPROF_TESTS endif WITH_HEAP_PROFILER endif WITH_DEBUGALLOC ### ------- CPU profiler if WITH_CPU_PROFILER perftoolsinclude_HEADERS += src/gperftools/profiler.h ### Making the library lib_LTLIBRARIES += libprofiler.la libprofiler_la_SOURCES = src/profiler.cc \ src/profile-handler.cc \ src/profiledata.cc libprofiler_la_LIBADD = libstacktrace.la libcommon.la # We have to include ProfileData for profiledata_unittest CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStartWithOptions|ProfilerStop|ProfilerFlush|ProfilerEnable|ProfilerDisable|ProfilingIsEnabledForAllThreads|ProfilerRegisterThread|ProfilerGetCurrentState|ProfilerState|ProfileData|ProfileHandler|ProfilerGetStackTrace)' libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS) \ -version-info @PROFILER_SO_VERSION@ ### Unittests TESTS += getpc_test getpc_test_SOURCES = src/tests/getpc_test.cc src/getpc.h TESTS += profiledata_unittest profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc src/profiledata.cc profiledata_unittest_CPPFLAGS = $(gtest_CPPFLAGS) profiledata_unittest_LDADD = libstacktrace.la libcommon.la libgtest.la TESTS += profile_handler_unittest profile_handler_unittest_SOURCES = src/tests/profile-handler_unittest.cc src/profile-handler.cc profile_handler_unittest_CPPFLAGS = $(gtest_CPPFLAGS) profile_handler_unittest_LDADD = libstacktrace.la libcommon.la libgtest.la if !SKIP_PPROF_TESTS TESTS += profiler_unittest.sh$(EXEEXT) profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh noinst_SCRIPTS += $(profiler_unittest_sh_SOURCES) profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(profiler_unittest_sh_SOURCES) \ profiler_unittest rm -f $@ cp -p $(top_srcdir)/$(profiler_unittest_sh_SOURCES) $@ # These are sub-programs used by profiler_unittest.sh noinst_PROGRAMS += profiler_unittest profiler_unittest_SOURCES = src/tests/profiler_unittest.cc \ src/tests/testutil.cc profiler_unittest_LDADD = libprofiler.la endif !SKIP_PPROF_TESTS endif WITH_CPU_PROFILER ### ------- CPU and heap profiler, in one! # Ideally, folks who wanted to use both tcmalloc and libprofiler, # could just link them both into their application. But while this # works fine for .so files, it does not for .a files. The easiest way # around this -- and I've tried a bunch of the hard ways -- is to just # to create another set of libraries that has both functionality in it. if WITH_HEAP_PROFILER_OR_CHECKER if WITH_CPU_PROFILER lib_LTLIBRARIES += libtcmalloc_and_profiler.la libtcmalloc_and_profiler_la_SOURCES = $(libtcmalloc_la_SOURCES) $(libprofiler_la_SOURCES) libtcmalloc_and_profiler_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) $(libprofiler_la_CXXFLAGS) # Since this library is meant to be used as a .a, I don't worry as much # about .so versioning. I just give the libtcmalloc version number. libtcmalloc_and_profiler_la_LDFLAGS = -version-info @TCMALLOC_AND_PROFILER_SO_VERSION@ \ $(AM_LDFLAGS) libtcmalloc_and_profiler_la_LIBADD = $(libtcmalloc_la_LIBADD) TESTS += tcmalloc_and_profiler_unittest tcmalloc_and_profiler_unittest_SOURCES = $(tcmalloc_both_unittest_srcs) tcmalloc_and_profiler_unittest_LDFLAGS = $(tcmalloc_both_unittest_lflags) tcmalloc_and_profiler_unittest_CPPFLAGS = $(gtest_CPPFLAGS) tcmalloc_and_profiler_unittest_LDADD = libtcmalloc_and_profiler.la libgtest.la endif WITH_CPU_PROFILER endif WITH_HEAP_PROFILER_OR_CHECKER ## ^^^^ END OF RULES TO MAKE YOUR LIBRARIES, BINARIES, AND UNITTESTS # This should always include $(TESTS), but may also include other # binaries that you compile but don't want automatically installed. # We'll add to this later, on a library-by-library basis noinst_PROGRAMS += $(TESTS) # http://linux.die.net/man/1/pkg-config, http://pkg-config.freedesktop.org/wiki pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libtcmalloc_minimal.pc if WITH_DEBUGALLOC pkgconfig_DATA += libtcmalloc_minimal_debug.pc endif WITH_DEBUGALLOC if WITH_HEAP_PROFILER_OR_CHECKER pkgconfig_DATA += libtcmalloc.pc if WITH_DEBUGALLOC pkgconfig_DATA += libtcmalloc_debug.pc endif WITH_DEBUGALLOC endif WITH_HEAP_PROFILER_OR_CHECKER if WITH_CPU_PROFILER pkgconfig_DATA += libprofiler.pc endif WITH_CPU_PROFILER CLEANFILES = $(pkgconfig_DATA) libtcmalloc.pc: Makefile echo 'prefix=$(prefix)' > "$@".tmp echo 'exec_prefix='`echo '$(exec_prefix)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp echo 'libdir='`echo '$(libdir)' | sed 's@^$(exec_prefix)@$${exec_prefix}@'` >> "$@".tmp echo 'includedir='`echo '$(includedir)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp echo '' >> "$@".tmp echo 'Name: $(PACKAGE)' >> "$@".tmp echo 'Version: $(VERSION)' >> "$@".tmp echo 'Description: Performance tools for C++' >> "$@".tmp echo 'URL: https://github.com/gperftools/gperftools' >> "$@".tmp echo 'Requires: $(UNWIND_PC_DEP)' >> "$@".tmp echo 'Libs: -L$${libdir} -ltcmalloc' >> "$@".tmp echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp echo 'Cflags: -I$${includedir}' >> "$@".tmp mv -f "$@".tmp "$@" libtcmalloc_minimal.pc: libtcmalloc.pc echo 'prefix=$(prefix)' > "$@".tmp echo 'exec_prefix='`echo '$(exec_prefix)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp echo 'libdir='`echo '$(libdir)' | sed 's@^$(exec_prefix)@$${exec_prefix}@'` >> "$@".tmp echo 'includedir='`echo '$(includedir)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp echo '' >> "$@".tmp echo 'Name: $(PACKAGE)' >> "$@".tmp echo 'Version: $(VERSION)' >> "$@".tmp echo 'Description: Performance tools for C++' >> "$@".tmp echo 'URL: https://github.com/gperftools/gperftools' >> "$@".tmp echo 'Requires:' >> "$@".tmp echo 'Libs: -L$${libdir} -ltcmalloc_minimal' >> "$@".tmp echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp echo 'Cflags: -I$${includedir}' >> "$@".tmp mv -f "$@".tmp "$@" libtcmalloc_debug.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_debug/ > "$@" libtcmalloc_minimal_debug.pc: libtcmalloc_minimal.pc cat libtcmalloc_minimal.pc | sed s/-ltcmalloc_minimal/-ltcmalloc_minimal_debug/ > "$@" libprofiler.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-lprofiler/ > "$@" $(top_distdir)/ChangeLog: if test ! -f $(top_srcdir)/ChangeLog ; \ then git --git-dir=$(top_srcdir)/.git --work-tree=$(top_srcdir) \ log --stat -M -C --name-status --no-color \ | fmt --split-only >$(top_distdir)/ChangeLog; \ else cp $(top_srcdir)/ChangeLog $(top_distdir)/ChangeLog; fi EXTRA_DIST = $(SCRIPTS) \ src/windows/get_mangled_names.cc src/windows/override_functions.cc \ src/windows/CMakeLists.txt \ $(WINDOWS_EXTRA) \ gperftools.sln vsprojects vendor \ $(top_srcdir)/src/*h $(top_srcdir)/src/base/*h \ $(top_srcdir)/benchmark/*h \ $(top_srcdir)/src/tests/*h \ $(top_srcdir)/src/windows/*h $(top_srcdir)/src/gperftools/*h \ CMakeLists.txt cmake \ generic-config/config.h .bazelrc BUILD.bazel MODULE.bazel # Windows wants write permission to .vcxproj files and maybe even sln files. dist-hook: $(top_distdir)/ChangeLog test -e "$(distdir)/vsprojects" \ && chmod -R u+w $(distdir)/*.sln $(distdir)/vsprojects/ rm -rf $(distdir)/vendor/googletest/googletest/src/.deps rm -rf $(distdir)/vendor/libbacktrace/.deps rm -rf $(distdir)/vendor/libbacktrace-integration/.deps rm -f $(distdir)/src/config.h gperftools-gperftools-2.18/NEWS000066400000000000000000001715051513545575200165360ustar00rootroot00000000000000== 23 January 2026 gperftools 2.18 is out! This release contains a number of improvements for the bazel build system, in particular for Windows. Plus a number of correctness fixes. Notable changes: * Correctness of C23 sized deallocation (free_sized) vs realloc has been fixed. Previously, free_sized could crash the process when used on reallocated objects. This also significantly changes the behavior of realloc. Previously, we had heuristics to avoid shrinking if the new size was at least 50% of the old size, and to pad small growths to at least 1.25x the original size. These heuristics have been removed to ensure compatibility with free_sized. * Bazel build support for Windows has been significantly improved, now working with MinGW and MSVC. * We now have an experimental :tcmalloc_minimal_nopatch Bazel target for Windows. * Fast TLS is now enabled for clang-mingw builds on Windows. * Building with 256k logical pages on 32-bit targets is fixed. Thanks to GitHub user LeyviRose for reporting the issue. * Several fixes to Valgrind integration were made. Thanks to GitHub user stefvanvlierberghe for reporting and advocating for these changes. * CPU profiler now uses a different mechanism to force child processes to use the pid in the cpu profile file name. Previously, we used a kludge that crashed certain software that insisted on valid UTF-8 in environment variables. See GitHub issues https://github.com/gperftools/gperftools/issues/1044 and https://github.com/gperftools/gperftools/issues/1603. * We now properly recognize SPARCv9 cache line length. Thanks to Nia Alarie for the patch. * Basic support for compile_commands.json generation was added, enabling nicer integration with modern IDEs. * Matthieu MOREL contributed a Bazel 9 compatibility fix. Please find the list of tickets explicitly closed by this release here: https://github.com/gperftools/gperftools/issues?q=label%3A%22fixed-in-2.18%22%20 == 15 August 2025 gperftools 2.17.2 is out! Couple bugs were found in the recently introduced changes. So this is another point release with some fixes. == 13 August 2025 gperftools 2.17.1 is out! There was just one fix submitted since 2.17. graysky has contributed build fix for (legacy, 32-bit) ARMs. Huge thanks! == 4 August 2025 gperftools 2.17 is out! We have had a few relatively simple updates since the RC release. * Salvatore Dipietro has contributed SB instruction support for spinlock delay loops on newer ARMs. * libgcc backtrace capturing method now handles deep backtraces better. * PPC+musl users can now workaround some issues building PPC-specific backtrace code by adding TCMALLOC_DISABLE_PPC_FRAME_POINTER_BACKTRACER preprocessor define. Much thanks to Josef Schlehofer for reporting the problem. See details in https://github.com/gperftools/gperftools/issues/1602. * Jackie Cui has contributed a small change to the page heap span selection logic that makes a big difference in reducing the amount of used memory in some workloads. See https://github.com/gperftools/gperftools/pull/1604 for further details. Much thanks to all the contributors. == 6 March 2025 gperftools 2.17rc is out! 2.17 headline changes are removal of heap leak checker and removal of legacy Perl pprof implementation. People should install and use much, much improved pprof implementation from github.com/google/pprof. Here is a complete list of reasonably notable changes: * [headline] heap leak checker has been amputated, as promised earlier * [headline] we don't ship pprof anymore. People need to get modern and awesome pprof implementation from github.com/google/pprof * we now have some basic CI infrastructure via Github Actions * we now have basic Bazel support * our docs have been slightly updated and converted to AsciiDoc format * we now implement C23 free{,_aligned}_sized functions (but no libc-s offer those yet anyway) * FreeBSD bits don't depend on procfs anymore (proc maps iterator was broken anyway; now it works) * we don't offer mmap profiling anymore. It wasn't entirely complete for some years now, and killing it has eliminated a lot of complexity. MMap hooks are still part of ABI, but they do nothing. Please find the list of tickets explicitly closed by this release here: https://github.com/gperftools/gperftools/issues?q=label%3A%22fixed-in-2.17%22%20 Many thanks for the following contributions: * Alex Faxa has contributed (partial) make install support for cmake bits * Andrey Semashev contributed one build fix and another fix for the test failure == 25 September 2024 gperftools 2.16 is out! Only minor fixes have been made since RC release. See NEWS entry for RC release for actual set of changes. == 16 September 2024 gperftools 2.16rc is out! This release doesn't have major fixes or big headline features, but it has quite a lot of internal modernizations and cleanups. By the number of commits, 2.16 is going to be our biggest release ever. This release's main focus was making our code and building infrastructure simpler, more straightforward, more portable, and more modern. Please note that the gperftools 2.16 release will be the last release with the heap leak checker included. The time has come to drop this feature entirely. All users should migrate to relevant gcc/clang sanitizers. Here are the most notable changes: * we've upgraded our C++ standard to C++ 17. Some fraction of our code base was modernized. * We've integrated (vendored copy of) GoogleTest, and most tests now use it. GoogleTest has helped us eliminate some legacy code and reduce the number of tests that use shell scripts. * There are no more unnecessary wrappers around mutexes and threads for unit tests. We now use C++ standard mutexes and threads in our tests. * We've done the bulk of the work necessary to enable hidden visibility. The most significant change is that tests no longer reach into libtcmalloc's guts. We use a special TestingPortal interface instead. We now offer the --enable-hidden-visibility configure option, which does what it says. But please note that hidden visibility is off by default for now. * autotools build was significantly refactored, modernized and simplified. * The cmake build has also been radically simplified. The previous version attempted to duplicate the same complexity that we had in the autotools build and did not do it very well. More tests now pass under cmake. But please note that cmake support is still not entirely functional, and we're not yet able to promise anything about it. * Thread-local storage access and emergency malloc integration have been reworked. We now support emergency malloc even on systems with emutls and similarly "bad" TLS support. As a result, backtracing is now more reliable (e.g., on QNX). * OSX operator new/delete performance has been improved. OSX's malloc performance is badly compromised by its support of malloc zones, so we cannot help much (the same applies to much of our competition among memory allocators). But the C++ new/delete API doesn't have to integrate with this stuff, so we now directly replace those functions for a sizeable speedup. Note that OSX performance is still not on par with other "prime tier" OSes due to its lack of efficient TLS support. * Long deprecated google/ headers have been deleted (use, e.g., "gperftools/tcmalloc.h" instead) * All clang builds now use -Wthread-safety and actually check thread-safety declarations * Our code has stopped being incompatible with _TIME_BITS=64 on modern GNU Linux systems (relevant only for 32-bit systems) * OpenSolaris build has been verified and fixed when needed Thanks to the following people for code contributions: * Github user oPiZiL (build fix for gcc 7.5) * Github user zhangdexin (qnx fixes) * Ishant Goyal (support for configuring minimal per-thread cache size) * Lennox Ho (several build fixes and several fixes around Windows support) * Olivier Langlois * Sergey Fedorovhas (another fix for building gperftools on old PPC OSX computers) * Xiang.Lin (several OSX fixes) * Yikai Zhao (aarch64 generic_fp stack frame validation) You can find the list of all GitHub issues fixes in this release here: https://github.com/gperftools/gperftools/issues?q=label%3Afixed-in-2.16+is%3Aclosed == 5 Jan 2024 gperftools 2.15 is out! This release has the following bug fixes: * Xiaowei Wang has pointed out the pthread linking issue on cmake on older glibcs (where -pthread is not implicit). See https://github.com/gperftools/gperftools/pull/1473 for more details. * Mikael Simberg and Tom "spot" Callaway have pointed out the missing symbols issue when linking PPC or i386 builds. https://github.com/gperftools/gperftools/issues/1474 has all the details. Huge thanks to all contributors! == 31 Dec 2023 gperftools 2.14 is out! This release has the following set of notable changes: * Roman Geissler has contributed a fix to nasty initialization bug introduced in 2.13 (see github issue #1452 for one example where it fails). * spinlock delay support now has proper windows support. Instead of simply sleeping, it uses WaitOnAddress (which is basically windows equivalent of futexes). This improvement was contributed by Lennox Ho. * we now have basic QNX support (basic malloc + heap profiler) championed by Xiang.Lin. Thanks! Do note, however, that QNX doesn't provide SIGPROF ticks, so there will be no cpu profiler support on this OS. * Yikai Zhao has contributed several fixes to important corner cases of generic_fp stacktrace method. * several people have contributed various improvements to our cmake build: Lennox Ho, Sergey Fedorov, Mateusz Jakub Fila. But do note that cmake build is still incomplete and best-effort. * Julian Schroeder have fixed generic_fp incompatibility with ARM pointer auth. * Mateusz Jakub Fila has contributed implementation of mallocinfo2 function (64-bit version of mallinfo). * Lennox Ho has updated C malloc extension shims to include {Set,Get}MemoryReleaseRate. * Lennox Ho has contributed the ability to disable malloc functions patching on windows when TCMALLOC_DISABLE_REPLACEMENT=1 environment variable is set. * User poljak181 has contributed a fix to infinite recursion in some cases of malloc hooks (or user-replaced operator new) and MallocExtension::instance(). * Sergey Fedorov has contributed a fix to use MAP_ANON on some older OSes without MAP_ANONYMOUS. * the way we detect working ucontext->pc extraction method was reworked and is now fully compile-time as opposed to config-time. This means no more duplication and mismatches between autoconf and cmake bits in this area. List of relevant tickets can be seen online at: https://github.com/gperftools/gperftools/issues?q=label%3Afixed-in-2.14+ == 11 Sep 2023 gperftools 2.13 is out! This release includes a few minor fixes: * Ivan Dlugos has fixed some issues with cmake and config.h defines. * 32-bit builds no longer require 64-bit atomics (which we wrongly introduced in 2.11 and which broke builds on some 32-bit architectures). * generic_fp backtracing method now uses robust address probing method. The previous approach had occasional false positives, which caused occasional rare crashes. * In some cases, MSVC generated TrivialOnce machine code that deadlocked programs on startup. The issue is now fixed. == 24 Aug 2023 gperftools 2.12 is out! Brett T. Warden contributed one significant fix. After a change in the previous release, we installed broken pkg-config files. Brett noticed and fixed that. Huge thanks! == 14 Aug 2023 gperftools 2.11 is out! Few minor fixes since rc couple weeks ago. Plus couple notable contributions: * Artem Polyakov has contributed auto-detection of several MPI systems w.r.t. filenames used by HEAPPROFILE and CPUPROFILE environment variables. Also, we now support HEAPPROFILE_USE_PID and CPUPROFILE_USE_PID environment variables that force profile filenames to have pid appended. Which will be useful for some programs that fork for parallelism. See https://github.com/gperftools/gperftools/pull/1263 for details. * Ken Raffenetti has extended MPI detection mentioned above with detection of MPICH system. Thanks a lot! == 31 July 2023 gperftools 2.11rc is out! Most notable change is that Linux/aarch64 and Linux/riscv are now fully supported. That is, all unit tests pass on those architectures (previously the heap leak checker was broken). Also notable is that heap leak checker support is officially deprecated as of this release. All bug fixes from now are on a best effort basis. For clarity we also declare that it is only expected to work (for some definition of work) on Linux/x86 (all kinds), Linux/aarch64, Linux/arm, Linux/ppc (untested as of this writing) and Linux/mips (untested as well). While some functionality worked in the past on BSDs, it was never fully functional; and will never be. We strongly recommend everyone to switch to asan and friends. For major internal changes it is also worth mentioning that we now fully switched to C++-11 std::atomic. All custom OS- and arch-specific atomic bits have been removed at last. Another notable change is that mmap and sbrk hooks facility is now no-op. We keep API and ABI for formal compatibility, but the calls to add mmap/sbrk hooks do nothing and return an error (whenever possible as part of API). There seem to be no users of it anyways, and mmap replacement API that is part of that facility really screwed up 64-bit offsets on (some/most) 32-bit systems. Internally for heap profiler and heap checker we have a new, but non-public API (see mmap_hook.h). Most tests now pass on NetBSD x86-64 (I tested on version 9.2). And only one that fails is new stacktrace test for stacktraces from signal handler (so there could be some imperfections for cpu profiles). We don't warn people away from the libgcc stacktrace capturing method anymore. In fact users on most recent glibc-s are advised to use it (pass --enable-libgcc-unwinder-by-default). This is thanks to the dl_find_object API offered by glibc which allows this implementation to be fully async-signal-safe. Modern Linux distros should from now on build their gperftools package with this enabled (other than those built on top of musl). generic_fp and generic_fp_unsafe stacktrace capturing methods have been expanded for more architectures and even some basic non-Linux support. We have completely removed old x86-specific frame pointer stacktrace implementation in favor of those 2. _unsafe one should be roughly equivalent to the old x86 method. And 'safe' one is recommended as a new default for those who want FP-based stacktracing. Safe implementation robustly checks memory before accessing it, preventing unlikely, but not impossible crashes when frame pointers are bogus. On platforms that support it, we now build gperftools with "-fno-omit-frame-pointer -momit-leaf-frame-pointer". This makes gperftools mostly frame-pointer-ful, but without performance hit in places that matter (this is how Google builds their binaries BTW). That should cover gcc (at least) on x86, aarch64 and riscv. Intention for this change is to make distro-shipped libtcmalloc.so compatible with frame-pointer stacktrace capturing (for those who still do heap profiling, for example). Of course, passing --enable-frame-pointers still gives you full frame pointers (i.e. even for leaf functions). There is now support for detecting actual page size at runtime. tcmalloc will now allocate memory in units of this page size. It particularly helps on arms with 64k pages to return memory back to the kernel. But it is somewhat controversial, because it effectively bumps tcmalloc logical page size on those machines potentially increasing fragmentation. In any case, there is now a new environment variable TCMALLOC_OVERRIDE_PAGESIZE allowing people to override this check. I.e. to either reduce effective page size down to tcmalloc's logical page size or to increase it. MallocExtension::MarkThreadTemporarilyIdle has been changed to be identical to MarkThreadIdle. MarkThreadTemporarilyIdle is believed to be unused, anyways. See issue #880 for details. There are a whole bunch of smaller fixes. Many of those smaller fixes had no associated ticket, but some had. People are advised to see here for list of notable tickets closed in this release: https://github.com/gperftools/gperftools/issues?q=label%3Afixed-in-2.11+ Some of those tickets are quite notable (fixes for rare deadlocks in cpu profiler ProfilerStop or while capturing heap growth stacktraces (aka growthz)). Here is list of notable contributions: * Chris Cambly has contributed initial support for AIX * Ali Saidi has contributed SpinlockPause implementation for aarch64 * Henrik Reinstädtler has contributed fix for cpuprofiler on aarch64 OSX * Gabriel Marin has backported Chromium's commit for always sanity checking large frees * User zhangyiru has contributed a fix to report the number of leaked bytes as size_t instead of (usually 32-bit) int. * Sergey Fedorov has contributed some fix for building on older ppc-based OSX-es * User tigeran has removed unused using declaration Huge thanks to all contributors. == 30 May 2022 == gperftools 2.10 is out! Here are notable changes: * Matt T. Proud contributed documentation fix to call Go programming language by it's true name instead of golang. * Robert Scott contributed debugallocator feature to use readable (PROT_READ) fence pages. This is activated by TCMALLOC_PAGE_FENCE_READABLE environment veriable. * User stdpain contributed fix for cmake detection of libunwind. * Natale Patriciello contributed fix for OSX Monterey support. * Volodymyr Nikolaichuk contributed support for returning memory back to OS by using mmap with MAP_FIXED and PROT_NONE. It is off by default and enabled by preprocessor define: FREE_MMAP_PROT_NONE. This should help OSes that don't support Linux-style madvise MADV_DONTNEED or BSD-style MADV_FREE. * Jingyun Hua has contributed basic support for LoongArch. * Github issue #1338 of failing to build on some recent musl versions has been fixed. * Github issue #1321 of failing to ship cmake bits with .tar.gz archive has been fixed. == 2 March 2021 == gperftools 2.9.1 is out! Minor fixes landed since previous release: * OSX builds new prefer backtrace() and have somewhat working heap sampling. * Incorrect assertion failure was fixed that crashed tcmalloc if assertions were on and sized delete was used. More details in github issue #1254. == 21 February 2021 == gperftools 2.9 is out! Few more changes landed compared to rc: * Venkatesh Srinivas has contributed thread-safety annotations support. * couple more unit test bugs that caused tcmalloc_unittest to fail on recent clang has been fixed. * usage of unsupportable linux_syscall_support.h has been removed from few places. Building with --disable-heap-checker now completely avoids it. Expect complete death of this header in next major release. == 14 February 2021 == gperftools 2.9rc is out! Here are notable changes: * Jarno Rajahalme has contributed fix for crashing bug in syscalls support for aarch64. * User SSE4 has contributed basic support for Elbrus 2000 architecture (!) * Venkatesh Srinivas has contributed cleanup to atomic ops. * Đoàn Trần Công Danh has fixed cpu profiler compilation on musl. * there is now better backtracing support for aarch64 and riscv. x86-64 with frame pointers now also defaults to this new "generic" frame pointer backtracer. * emergency malloc is now enabled by default. Fixes hang on musl when libgcc backtracer is enabled. * bunch of legacy config tests has been removed == 20 December 2020 == gperftools 2.8.1 is out! Here are notable changes: * previous release contained change to release memory without page heap lock, but this change had at least one bug that caused to crashes and corruption when running under aggressive decommit mode (this is not default). While we check for other bugs, this feature was reverted. See github issue #1204 and issue #1227. * stack traces depth captured by gperftools is now up to 254 levels deep. Thanks to Kerrick Staley for this small but useful tweak. * Levon Ter-Grigoryan has contributed small fix for compiler warning. * Grant Henke has contributed updated detection of program counter register for OS X on arm64. * Tim Gates has contributed small typo fix. * Steve Langasek has contributed basic build fixes for riscv64 (!). * Isaac Hier and okhowang have contributed premiliminary port of build infrastructure to cmake. This works, but it is very premiliminary. Autotools-based build is the only officially supported build for now. == 6 July 2020 == gperftools 2.8 is out! Here are notable changes: * ProfilerGetStackTrace is now officially supported API for libprofiler. Contributed by Kirill Müller. * Build failures on mingw were fixed. This fixed issue #1108. * Build failure of page_heap_test on MSVC was fixed. * Ryan Macnak contributed fix for compiling linux syscall support on i386 and recent GCCs. This fixed issue #1076. * test failures caused by new gcc 10 optimizations were fixed. Same change also fixed tests on clang. == 8 Mar 2020 == gperftools 2.8rc is out! Here are notable changes: * building code now requires c++11 or later. Bundled MSVC project was converted to Visual Studio 2015. * User obones contributed fix for windows x64 TLS callbacks. This fixed leak of thread caches on thread exists in 64-bit windows. * releasing memory back to kernel is now made with page heap lock dropped. * HoluWu contributed fix for correct malloc patching on debug builds on windows. This configuration previously crashed. * Romain Geissler contributed fix for tls access during early tls initialization on dlopen. * large allocation reports are now silenced by default. Since not all programs want their stderr polluted by those messages. Contributed by Junhao Li. * HolyWu contributed improvements to MSVC project files. Notably, there is now project for "overriding" version of tcmalloc. * MS-specific _recalloc is now correctly zeroing only malloced part. This fix was contributed by HolyWu. * Brian Silverman contributed correctness fix to sampler_test. * Gabriel Marin ported few fixes from chromium's fork. As part of those fixes, we reduced number of static initializers (forbidden in chromium). Also we now syscalls via syscall function instead of reimplementing direct way to make syscalls on each platform. * Brian Silverman fixed flakiness in page heap test. * There is now configure flag to skip installing perl pprof, since external golang pprof is much superior. --disable-deprecated-pprof is the flag. * Fabric Fontaine contributed fixes to drop use of nonstandard __off64_t type. * Fabrice Fontaine contributed build fix to check for presence of nonstandard __sbrk functions. It is only used by mmap hooks code and (rightfully) not available on musl. * Fabrice Fontaine contributed build fix around mmap64 macro and function conflict in same cases. * there is now configure time option to enable aggressive decommit by default. Contributed by Laurent Stacul. --enable-aggressive-decommit-by-default is the flag. * Tulio Magno Quites Machado Filho contributed build fixes for ppc around ucontext access. * User pkubaj contributed couple build fixes for FreeBSD/ppc. * configure now always assumes we have mmap. This fixes configure failures on some linux guests inside virtualbox. This fixed issue #1008. * User shipujin contributed syscall support fixes for mips64 (big and little endian). * Henrik Edin contributed configurable support for wide range of malloc page sizes. 4K, 8K, 16K, 32K, 64K, 128K and 256K are now supported via existing --with-tcmalloc-pagesize flag to configure. * Jon Kohler added overheads fields to per-size-class textual stats. Stats that are available via MallocExtension::instance()->GetStats(). * tcmalloc can now avoid fallback from memfs to default sys allocator. TCMALLOC_MEMFS_DISABLE_FALLBACK switches this on. This was contributed by Jon Kohler. * Ilya Leoshkevich fixed mmap syscall support on s390. * Todd Lipcon contributed small build warning fix. * User prehistoricpenguin contributed misc source file mode fixes (we still had few few c++ files marked executable). * User invalid_ms_user contributed fix for typo. * Jakub Wilk contributed typos fixes. == 29 Apr 2018 == gperftools 2.7 is out! Few people contributed minor, but important fixes since rc. Changes: * bug in span stats printing introduced by new scalable page heap change was fixed. * Christoph Müllner has contributed couple warnings fixes and initial support for aarch64_ilp32 architecture. * Ben Dang contributed documentation fix for heap checker. * Fabrice Fontaine contributed fixed for linking benchmarks with --disable-static. * Holy Wu has added sized deallocation unit tests. * Holy Wu has enabled support of sized deallocation (c++14) on recent MSVC. * Holy Wu has fixed MSVC build in WIN32_OVERRIDE_ALLOCATORS mode. This closed issue #716. * Holy Wu has contributed cleanup of config.h used on windows. * Mao Huang has contributed couple simple tcmalloc changes from chromium code base. Making our tcmalloc forks a tiny bit closer. * issue #946 that caused compilation failures on some Linux clang installations has been fixed. Much thanks to github user htuch for helping to diagnose issue and proposing a fix. * Tulio Magno Quites Machado Filho has contributed build-time fix for PPC (for problem introduced in one of commits since RC). == 18 Mar 2018 == gperftools 2.7rc is out! Changes: * Most notable change in this release is that very large allocations (>1MiB) are now handled be O(log n) implementation. This is contributed by Todd Lipcon based on earlier work by Aliaksei Kandratsenka and James Golick. Special thanks to Alexey Serbin for contributing OSX fix for that commit. * detection of sized deallocation support is improved. Which should fix another set of issues building on OSX. Much thanks to Alexey Serbin for reporting the issue, suggesting a fix and verifying it. * Todd Lipcon made a change to extend page heaps freelists to 1 MiB (up from 1MiB - 8KiB). This may help a little for some workloads. * Ishan Arora contributed typo fix to docs == 9 Dec 2017 == gperftools 2.6.3 is out! Just two fixes were made in this release: * Stephan Zuercher has contributed a build fix for some recent XCode versions. See issue #942 for more details. * assertion failure on some windows builds introduced by 2.6.2 was fixed. Thanks to github user nkeemik for reporting it and testing fix. See issue #944 for more details. == 30 Nov 2017 == gperftools 2.6.2 is out! Most notable change is recently added support for C++17 over-aligned allocation operators contributed by Andrey Semashev. I've extended his implemention to have roughly same performance as malloc/new. This release also has native support for C11 aligned_alloc. Rest is mostly bug fixes: * Jianbo Yang has contributed a fix for potentially severe data race introduced by malloc fast-path work in gperftools 2.6. This race could cause occasional violation of total thread cache size constraint. See issue #929 for more details. * Correct behavior in out-of-memory condition in fast-path cases was restored. This was another bug introduced by fast-path optimization in gperftools 2.6 which caused operator new to silently return NULL instead of doing correct C++ OOM handling (calling new_handler and throwing bad_alloc). * Khem Raj has contributed couple build fixes for newer glibcs (ucontext_t vs struct ucontext and loff_t definition) * Piotr Sikora has contributed build fix for OSX (not building unwind benchmark). This was issue #910 (thanks to Yuriy Solovyov for reporting it). * Dorin Lazăr has contributed fix for compiler warning * issue #912 (occasional deadlocking calling getenv too early on windows) was fixed. Thanks to github user shangcangriluo for reporting it. * Couple earlier lsan-related commits still causing occasional issues linking on OSX has been reverted. See issue #901. * Volodimir Krylov has contributed GetProgramInvocationName for FreeBSD * changsu lee has contributed couple minor correctness fixes (missing va_end() and missing free() call in rarely executed Symbolize path) * Andrew C. Morrow has contributed some more page heap stats. See issue #935. * some cases of built-time warnings from various gcc/clang versions about throw() declarations have been fixes. == 9 July 2017 == gperftools 2.6.1 is out! This is mostly bug-fixes release. * issue #901: build issue on OSX introduced in last-time commit in 2.6 was fixed (contributed by Francis Ricci) * tcmalloc_minimal now works on 32-bit ABI of mips64. This is issue #845. Much thanks to Adhemerval Zanella and github user mtone. * Romain Geissler contributed build fix for -std=c++17. This is pull request #897. * As part of fixing issue #904, tcmalloc atfork handler is now installed early. This should fix slight chance of hitting deadlocks at fork in some cases. == 4 July 2017 == gperftools 2.6 is out! * Kim Gräsman contributed documentation update for HEAPPROFILESIGNAL environment variable * KernelMaker contributed fix for population of min_object_size field returned by MallocExtension::GetFreeListSizes * commit 8c3dc52fcfe0 "issue-654: [pprof] handle split text segments" was reverted. Some OSX users reported issues with this commit. Given our pprof implementation is strongly deprecated it is best to drop recently introduced features rather than breaking it badly. * Francis Ricci contributed improvement for interaction with leak sanitizer. == 22 May 2017 == gperftools 2.6rc4 is out! Dynamic sized delete is disabled by default again. There is no hope of it working with eager dynamic symbols resolution (-z now linker flag). More details in https://bugzilla.redhat.com/show_bug.cgi?id=1452813 == 21 May 2017 == gperftools 2.6rc3 is out! gperftools compilation on older systems (e.g. rhel 5) was fixed. This was originally reported in github issue #888. == 14 May 2017 == gperftools 2.6rc2 is out! Just 2 small fixes on top of 2.6rc. Particularly, Rajalakshmi Srinivasaraghavan contributed build fix for ppc32. == 14 May 2017 == gperftools 2.6rc is out! Highlights of this release are performance work on malloc fast-path and support for more modern visual studio runtimes, and deprecation of bundled pprof. Another significant performance-affecting changes are reverting central free list transfer batch size back to 32 and disabling of aggressive decommit mode by default. Note, while we still ship perl implementation of pprof, everyone is strongly advised to use golang reimplementation of pprof from https://github.com/google/pprof. Here are notable changes in more details (and see ChangeLog for full details): * a bunch of performance tweaks to tcmalloc fast-path were merged. This speeds up critical path of tcmalloc by few tens of %. Well tuned and allocation-heavy programs should see substantial performance boost (should apply to all modern elf platforms). This is based on Google-internal tcmalloc changes for fast-path (with obvious exception of lacking per-cpu mode, of course). Original changes were made by Aliaksei Kandratsenka. And Andrew Hunter, Dmitry Vyukov and Sanjay Ghemawat contributed with reviews and discussions. * Architectures with 48 bits address space (x86-64 and aarch64) now use faster 2 level page map. This was ported from Google-internal change by Sanjay Ghemawat. * Default value of TCMALLOC_TRANSFER_NUM_OBJ was returned back to 32. Larger values have been found to hurt certain programs (but help some other benchmarks). Value can still be tweaked at run time via environment variable. * tcmalloc aggressive decommit mode is now disabled by default again. It was found to degrade performance of certain tensorflow benchmarks. Users who prefer smaller heap over small performance win can still set environment variable TCMALLOC_AGGRESSIVE_DECOMMIT=t. * runtime switchable sized delete support has be fixed and re-enabled (on GNU/Linux). Programs that use C++ 14 or later that use sized delete can again be sped up by setting environment variable TCMALLOC_ENABLE_SIZED_DELETE=t. Support for enabling sized deallication support at compile-time is still present, of course. * tcmalloc now explicitly avoids use of MADV_FREE on Linux, unless TCMALLOC_USE_MADV_FREE is defined at compile time. This is because performance impact of MADV_FREE is not well known. Original issue #780 raised by Mathias Stearn. * issue #786 with occasional deadlocks in stack trace capturing via libunwind was fixed. It was originally reported as Ceph issue: http://tracker.ceph.com/issues/13522 * ChangeLog is now automatically generated from git log. Old ChangeLog is now ChangeLog.old. * tcmalloc now provides implementation of nallocx. Function was originally introduced by jemalloc and can be used to return real allocation size given allocation request size. This is ported from Google-internal tcmalloc change contributed by Dmitry Vyukov. * issue #843 which made tcmalloc crash when used with erlang runtime was fixed. * issue #839 which caused tcmalloc's aggressive decommit mode to degrade performance in some corner cases was fixed. * Bryan Chan contributed support for 31-bit s390. * Brian Silverman contributed compilation fix for 32-bit ARMs * Issue #817 that was causing tcmalloc to fail on windows 10 and later, as well as on recent msvc was fixed. We now patch _free_base as well. * a bunch of minor documentaion/typos fixes by: Mike Gaffney , iivlev , savefromgoogle , John McDole , zmertens , Kirill Müller , Eugene , Ola Olsson , Mostyn Bramley-Moore * Tulio Magno Quites Machado Filho has contributed removal of deprecated glibc malloc hooks. * Issue #827 that caused intercepting malloc on osx 10.12 to fail was fixed, by copying fix made by Mike Hommey to jemalloc. Much thanks to Koichi Shiraishi and David Ribeiro Alves for reporting it and testing fix. * Aman Gupta and Kenton Varda contributed minor fixes to pprof (but note again that pprof is deprecated) * Ryan Macnak contributed compilation fix for aarch64 * Francis Ricci has fixed unaligned memory access in debug allocator * TCMALLOC_PAGE_FENCE_NEVER_RECLAIM now actually works thanks to contribution by Andrew Morrow. == 12 Mar 2016 == gperftools 2.5 is out! Just single bugfix was merged after rc2. Which was fix for issue #777. == 5 Mar 2016 == gperftools 2.5rc2 is out! New release contains just few commits on top of first release candidate. One of them is build fix for Visual Studio. Another significant change is that dynamic sized delete is now disabled by default. It turned out that IFUNC relocations are not supporting our advanced use case on all platforms and in all cases. == 21 Feb 2016 == gperftools 2.5rc is out! Here are major changes since 2.4: * we've moved to github! * Bryan Chan has contributed s390x support * stacktrace capturing via libgcc's _Unwind_Backtrace was implemented (for architectures with missing or broken libunwind). * "emergency malloc" was implemented. Which unbreaks recursive calls to malloc/free from stacktrace capturing functions (such us glib'c backtrace() or libunwind on arm). It is enabled by --enable-emergency-malloc configure flag or by default on arm when --enable-stacktrace-via-backtrace is given. It is another fix for a number common issues people had on platforms with missing or broken libunwind. * C++14 sized-deallocation is now supported (on gcc 5 and recent clangs). It is off by default and can be enabled at configure time via --enable-sized-delete. On GNU/Linux it can also be enabled at run-time by either TCMALLOC_ENABLE_SIZED_DELETE environment variable or by defining tcmalloc_sized_delete_enabled function which should return 1 to enable it. * we've lowered default value of transfer batch size to 512. Previous value (bumped up in 2.1) was too high and caused performance regression for some users. 512 should still give us performance boost for workloads that need higher transfer batch size while not penalizing other workloads too much. * Brian Silverman's patch finally stopped arming profiling timer unless profiling is started. * Andrew Morrow has contributed support for obtaining cache size of the current thread and softer idling (for use in MongoDB). * we've implemented few minor performance improvements, particularly on malloc fast-path. A number of smaller fixes were made. Many of them were contributed: * issue that caused spurious profiler_unittest.sh failures was fixed. * Jonathan Lambrechts contributed improved callgrind format support to pprof. * Matt Cross contributed better support for debug symbols in separate files to pprof. * Matt Cross contributed support for printing collapsed stack frame from pprof aimed at producing flame graphs. * Angus Gratton has contributed documentation fix mentioning that on windows only tcmalloc_minimal is supported. * Anton Samokhvalov has made tcmalloc use mi_force_{un,}lock on OSX instead of pthread_atfork. Which apparently fixes forking issues tcmalloc had on OSX. * Milton Chiang has contributed support for building 32-bit gperftools on arm8. * Patrick LoPresti has contributed support for specifying alternative profiling signal via CPUPROFILE_TIMER_SIGNAL environment variable. * Paolo Bonzini has contributed support configuring filename for sending malloc tracing output via TCMALLOC_TRACE_FILE environment variable. * user spotrh has enabled use of futex on arm. * user mitchblank has contributed better declaration for arg-less profiler functions. * Tom Conerly contributed proper freeing of memory allocated in HeapProfileTable::FillOrderedProfile on error paths. * user fdeweerdt has contributed curl arguments handling fix in pprof * Frederik Mellbin fixed tcmalloc's idea of mangled new and delete symbols on windows x64 * Dair Grant has contributed cacheline alignment for ThreadCache objects * Fredrik Mellbin has contributed updated windows/config.h for Visual Studio 2015 and other windows fixes. * we're not linking libpthread to libtcmalloc_minimal anymore. Instead libtcmalloc_minimal links to pthread symbols weakly. As a result single-threaded programs remain single-threaded when linking to or preloading libtcmalloc_minimal.so. * Boris Sazonov has contributed mips compilation fix and printf misue in pprof. * Adhemerval Zanella has contributed alignment fixes for statically allocated variables. * Jens Rosenboom has contributed fixes for heap-profiler_unittest.sh * gshirishfree has contributed better description for GetStats method. * cyshi has contributed spinlock pause fix. * Chris Mayo has contributed --docdir argument support for configure. * Duncan Sands has contributed fix for function aliases. * Simon Que contributed better include for malloc_hook_c.h * user wmamrak contributed struct timespec fix for Visual Studio 2015. * user ssubotin contributed typo in PrintAvailability code. == 10 Jan 2015 == gperftools 2.4 is out! The code is exactly same as 2.4rc. == 28 Dec 2014 == gperftools 2.4rc is out! Here are changes since 2.3: * enabled aggressive decommit option by default. It was found to significantly improve memory fragmentation with negligible impact on performance. (Thanks to investigation work performed by Adhemerval Zanella) * added ./configure flags for tcmalloc pagesize and tcmalloc allocation alignment. Larger page sizes have been reported to improve performance occasionally. (Patch by Raphael Moreira Zinsly) * sped-up hot-path of malloc/free. By about 5% on static library and about 10% on shared library. Mainly due to more efficient checking of malloc hooks. * improved stacktrace capturing in cpu profiler (due to issue found by Arun Sharma). As part of that issue pprof's handling of cpu profiles was also improved. == 7 Dec 2014 == gperftools 2.3 is out! Here are changes since 2.3rc: * (issue 658) correctly close socketpair fds on failure (patch by glider) * libunwind integration can be disabled at configure time (patch by Raphael Moreira Zinsly) * libunwind integration is disabled by default for ppc64 (patch by Raphael Moreira Zinsly) * libunwind integration is force-disabled for OSX. It was not used by default anyways. Fixes compilation issue I saw. == 2 Nov 2014 == gperftools 2.3rc is out! Most small improvements in this release were made to pprof tool. New experimental Linux-only (for now) cpu profiling mode is a notable big improvement. Here are notable changes since 2.2.1: * (issue-631) fixed debugallocation miscompilation on mmap-less platforms (courtesy of user iamxujian) * (issue-630) reference to wrong PROFILE (vs. correct CPUPROFILE) environment variable was fixed (courtesy of WenSheng He) * pprof now has option to display stack traces in output for heap checker (courtesy of Michael Pasieka) * (issue-636) pprof web command now works on mingw * (issue-635) pprof now handles library paths that contain spaces (courtesy of user mich...@sebesbefut.com) * (issue-637) pprof now has an option to not strip template arguments (patch by jiakai) * (issue-644) possible out-of-bounds access in GetenvBeforeMain was fixed (thanks to user abyss.7) * (issue-641) pprof now has an option --show_addresses (thanks to user yurivict). New option prints instruction address in addition to function name in stack traces * (issue-646) pprof now works around some issues of addr2line reportedly when DWARF v4 format is used (patch by Adam McNeeney) * (issue-645) heap profiler exit message now includes remaining memory allocated info (patch by user yurivict) * pprof code that finds location of /proc//maps in cpu profile files is now fixed (patch by Ricardo M. Correia) * (issue-654) pprof now handles "split text segments" feature of Chromium for Android. (patch by simonb) * (issue-655) potential deadlock on windows caused by early call to getenv in malloc initialization code was fixed (bug reported and fix proposed by user zndmitry) * incorrect detection of arm 6zk instruction set support (-mcpu=arm1176jzf-s) was fixed. (Reported by pedronavf on old issue-493) * new cpu profiling mode on Linux is now implemented. It sets up separate profiling timers for separate threads. Which improves accuracy of profiling on Linux a lot. It is off by default. And is enabled if both librt.f is loaded and CPUPROFILE_PER_THREAD_TIMERS environment variable is set. But note that all threads need to be registered via ProfilerRegisterThread. == 21 Jun 2014 == gperftools 2.2.1 is out! Here's list of fixes: * issue-626 was closed. Which fixes initialization statically linked tcmalloc. * issue 628 was closed. It adds missing header file into source tarball. This fixes for compilation on PPC Linux. == 3 May 2014 == gperftools 2.2 is out! Here are notable changes since 2.2rc: * issue 620 (crash on windows when c runtime dll is reloaded) was fixed == 19 Apr 2014 == gperftools 2.2rc is out! Here are notable changes since 2.1: * a number of fixes for a number compilers and platforms. Notably Visual Studio 2013, recent mingw with c++ threads and some OSX fixes. * we now have mips and mips64 support! (courtesy of Jovan Zelincevic, Jean Lee, user xiaoyur347 and others) * we now have aarch64 (aka arm64) support! (contributed by Riku Voipio) * there's now support for ppc64-le (by Raphael Moreira Zinsly and Adhemerval Zanella) * there's now some support of uclibc (contributed by user xiaoyur347) * google/ headers will now give you deprecation warning. They are deprecated since 2.0 * there's now new api: tc_malloc_skip_new_handler (ported from chromium fork) * issue-557: added support for dumping heap profile via signal (by Jean Lee) * issue-567: Petr Hosek contributed SysAllocator support for windows * Joonsoo Kim contributed several speedups for central freelist code * TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES environment variable now works * configure scripts are now using AM_MAINTAINER_MODE. It'll only affect folks who modify source from .tar.gz and want automake to automatically rebuild Makefile-s. See automake documentation for that. * issue-586: detect main executable even if PIE is active (based on patch by user themastermind1). Notably, it fixes profiler use with ruby. * there is now support for switching backtrace capturing method at runtime (via TCMALLOC_STACKTRACE_METHOD and TCMALLOC_STACKTRACE_METHOD_VERBOSE environment variables) * there is new backtrace capturing method using -finstrument-functions prologues contributed by user xiaoyur347 * few cases of crashes/deadlocks in profiler were addressed. See (famous) issue-66, issue-547 and issue-579. * issue-464 (memory corruption in debugalloc's realloc after memallign) is now fixed * tcmalloc is now able to release memory back to OS on windows (issue-489). The code was ported from chromium fork (by a number of authors). * Together with issue-489 we ported chromium's "aggressive decommit" mode. In this mode (settable via malloc extension and via environment variable TCMALLOC_AGGRESSIVE_DECOMMIT), free pages are returned back to OS immediately. * MallocExtension::instance() is now faster (based on patch by Adhemerval Zanella) * issue-610 (hangs on windows in multibyte locales) is now fixed The following people helped with ideas or patches (based on git log, some contributions purely in bugtracker might be missing): Andrew C. Morrow, yurivict, Wang YanQing, Thomas Klausner, davide.italiano@10gen.com, Dai MIKURUBE, Joon-Sung Um, Jovan Zelincevic, Jean Lee, Petr Hosek, Ben Avison, drussel, Joonsoo Kim, Hannes Weisbach, xiaoyur347, Riku Voipio, Adhemerval Zanella, Raphael Moreira Zinsly == 30 July 2013 == gperftools 2.1 is out! Just few fixes where merged after rc. Most notably: * Some fixes for debug allocation on POWER/Linux == 20 July 2013 == gperftools 2.1rc is out! As a result of more than a year of contributions we're ready for 2.1 release. But before making that step I'd like to create RC and make sure people have chance to test it. Here are notable changes since 2.0: * fixes for building on newer platforms. Notably, there's now initial support for x32 ABI (--enable-minimal only at this time)) * new getNumericProperty stats for cache sizes * added HEAP_PROFILER_TIME_INTERVAL variable (see documentation) * added environment variable to control heap size (TCMALLOC_HEAP_LIMIT_MB) * added environment variable to disable release of memory back to OS (TCMALLOC_DISABLE_MEMORY_RELEASE) * cpu profiler can now be switched on and off by sending it a signal (specified in CPUPROFILESIGNAL) * (issue 491) fixed race-ful spinlock wake-ups * (issue 496) added some support for fork-ing of process that is using tcmalloc * (issue 368) improved memory fragmentation when large chunks of memory are allocated/freed == 03 February 2012 == I've just released gperftools 2.0 The `google-perftools` project has been renamed to `gperftools`. I (csilvers) am stepping down as maintainer, to be replaced by David Chappelle. Welcome to the team, David! David has been an an active contributor to perftools in the past -- in fact, he's the only person other than me that already has commit status. I am pleased to have him take over as maintainer. I have both renamed the project (the Google Code site renamed a few weeks ago), and bumped the major version number up to 2, to reflect the new community ownership of the project. Almost all the [http://gperftools.googlecode.com/svn/tags/gperftools-2.0/ChangeLog changes] are related to the renaming. The main functional change from google-perftools 1.10 is that I've renamed the `google/` include-directory to be `gperftools/` instead. New code should `#include `/etc. (Most users of perftools don't need any perftools-specific includes at all, so this is mostly directed to "power users.") I've kept the old names around as forwarding headers to the new, so `#include ` will continue to work. (The other functional change which I snuck in is getting rid of some bash-isms in one of the unittest driver scripts, so it could run on Solaris.) Note that some internal names still contain the text `google`, such as the `google_malloc` internal linker section. I think that's a trickier transition, and can happen in a future release (if at all). === 31 January 2012 === I've just released perftools 1.10 There is an API-incompatible change: several of the methods in the `MallocExtension` class have changed from taking a `void*` to taking a `const void*`. You should not be affected by this API change unless you've written your own custom malloc extension that derives from `MallocExtension`, but since it is a user-visible change, I have upped the `.so` version number for this release. This release focuses on improvements to linux-syscall-support.h, including ARM and PPC fixups and general cleanups. I hope this will magically fix an array of bugs people have been seeing. There is also exciting news on the porting front, with support for patching win64 assembly contributed by IBM Canada! This is an important step -- perhaps the most difficult -- to getting perftools to work on 64-bit windows using the patching technique (it doesn't affect the libc-modification technique). `premable_patcher_test` has been added to help test these changes; it is meant to compile under x86_64, and won't work under win32. For the full list of changes, including improved `HEAP_PROFILE_MMAP` support, see the [http://gperftools.googlecode.com/svn/tags/google-perftools-1.10/ChangeLog ChangeLog]. === 24 January 2011 === The `google-perftools` Google Code page has been renamed to `gperftools`, in preparation for the project being renamed to `gperftools`. In the coming weeks, I'll be stepping down as maintainer for the perftools project, and as part of that Google is relinquishing ownership of the project; it will now be entirely community run. The name change reflects that shift. The 'g' in 'gperftools' stands for 'great'. :-) === 23 December 2011 === I've just released perftools 1.9.1 I missed including a file in the tarball, that is needed to compile on ARM. If you are not compiling on ARM, or have successfully compiled perftools 1.9, there is no need to upgrade. === 22 December 2011 === I've just released perftools 1.9 This change has a slew of improvements, from better ARM and freebsd support, to improved performance by moving some code outside of locks, to better pprof reporting of code with overloaded functions. The full list of changes is in the [http://google-perftools.googlecode.com/svn/tags/google-perftools-1.9/ChangeLog ChangeLog]. === 26 August 2011 === I've just released perftools 1.8.3 The star-crossed 1.8 series continues; in 1.8.1, I had accidentally removed some code that was needed for FreeBSD. (Without this code many apps would crash at startup.) This release re-adds that code. If you are not on FreeBSD, or are using FreeBSD with perftools 1.8 or earlier, there is no need to upgrade. === 11 August 2011 === I've just released perftools 1.8.2 I was incorrectly calculating the patch-level in the configuration step, meaning the TC_VERSION_PATCH #define in tcmalloc.h was wrong. Since the testing framework checks for this, it was failing. Now it should work again. This time, I was careful to re-run my tests after upping the version number. :-) If you don't care about the TC_VERSION_PATCH #define, there's no reason to upgrae. === 26 July 2011 === I've just released perftools 1.8.1 I was missing an #include that caused the build to break under some compilers, especially newer gcc's, that wanted it. This only affects people who build from source, so only the .tar.gz file is updated from perftools 1.8. If you didn't have any problems compiling perftools 1.8, there's no reason to upgrade. === 15 July 2011 === I've just released perftools 1.8 Of the many changes in this release, a good number pertain to porting. I've revamped OS X support to use the malloc-zone framework; it should now Just Work to link in tcmalloc, without needing `DYLD_FORCE_FLAT_NAMESPACE` or the like. (This is a pretty major change, so please feel free to report feedback at google-perftools@googlegroups.com.) 64-bit Windows support is also improved, as is ARM support, and the hooks are in place to improve FreeBSD support as well. On the other hand, I'm seeing hanging tests on Cygwin. I see the same hanging even with (the old) perftools 1.7, so I'm guessing this is either a problem specific to my Cygwin installation, or nobody is trying to use perftools under Cygwin. If you can reproduce the problem, and even better have a solution, you can report it at google-perftools@googlegroups.com. Internal changes include several performance and space-saving tweaks. One is user-visible (but in "stealth mode", and otherwise undocumented): you can compile with `-DTCMALLOC_SMALL_BUT_SLOW`. In this mode, tcmalloc will use less memory overhead, at the cost of running (likely not noticeably) slower. There are many other changes as well, too numerous to recount here, but present in the [http://google-perftools.googlecode.com/svn/tags/google-perftools-1.8/ChangeLog ChangeLog]. === 7 February 2011 === Thanks to endlessr..., who [http://code.google.com/p/google-perftools/issues/detail?id=307 identified] why some tests were failing under MSVC 10 in release mode. It does not look like these failures point toward any problem with tcmalloc itself; rather, the problem is with the test, which made some assumptions that broke under the some aggressive optimizations used in MSVC 10. I'll fix the test, but in the meantime, feel free to use perftools even when compiled under MSVC 10. === 4 February 2011 === I've just released perftools 1.7 I apologize for the delay since the last release; so many great new patches and bugfixes kept coming in (and are still coming in; I also apologize to those folks who have to slip until the next release). I picked this arbitrary time to make a cut. Among the many new features in this release is a multi-megabyte reduction in the amount of tcmalloc overhead uder x86_64, improved performance in the case of contention, and many many bugfixes, especially architecture-specific bugfixes. See the [http://google-perftools.googlecode.com/svn/tags/google-perftools-1.7/ChangeLog ChangeLog] for full details. One architecture-specific change of note is added comments in the [http://google-perftools.googlecode.com/svn/tags/perftools-1.7/README README] for using tcmalloc under OS X. I'm trying to get my head around the exact behavior of the OS X linker, and hope to have more improvements for the next release, but I hope these notes help folks who have been having trouble with tcmalloc on OS X. *Windows users*: I've heard reports that some unittests fail on Windows when compiled with MSVC 10 in Release mode. All tests pass in Debug mode. I've not heard of any problems with earlier versions of MSVC. I don't know if this is a problem with the runtime patching (so the static patching discussed in README_windows.txt will still work), a problem with perftools more generally, or a bug in MSVC 10. Anyone with windows expertise that can debug this, I'd be glad to hear from! === 5 August 2010 === I've just released perftools 1.6 This version also has a large number of minor changes, including support for `malloc_usable_size()` as a glibc-compatible alias to `malloc_size()`, the addition of SVG-based output to `pprof`, and experimental support for tcmalloc large pages, which may speed up tcmalloc at the cost of greater memory use. To use tcmalloc large pages, see the [http://google-perftools.googlecode.com/svn/tags/perftools-1.6/INSTALL INSTALL file]; for all changes, see the [http://google-perftools.googlecode.com/svn/tags/perftools-1.6/ChangeLog ChangeLog]. OS X NOTE: improvements in the profiler unittest have turned up an OS X issue: in multithreaded programs, it seems that OS X often delivers the profiling signal (from sigitimer()) to the main thread, even when it's sleeping, rather than spawned threads that are doing actual work. If anyone knows details of how OS X handles SIGPROF events (from setitimer) in threaded programs, and has insight into this problem, please send mail to google-perftools@googlegroups.com. To see if you're affected by this, look for profiling time that pprof attributes to `___semwait_signal`. This is work being done in other threads, that is being attributed to sleeping-time in the main thread. === 20 January 2010 === I've just released perftools 1.5 This version has a slew of changes, leading to somewhat faster performance and improvements in portability. It adds features like `ITIMER_REAL` support to the cpu profiler, and `tc_set_new_mode` to mimic the windows function of the same name. Full details are in the [http://google-perftools.googlecode.com/svn/tags/perftools-1.5/ChangeLog ChangeLog]. === 11 September 2009 === I've just released perftools 1.4 The major change this release is the addition of a debugging malloc library! If you link with `libtcmalloc_debug.so` instead of `libtcmalloc.so` (and likewise for the `minimal` variants) you'll get a debugging malloc, which will catch double-frees, writes to freed data, `free`/`delete` and `delete`/`delete[]` mismatches, and even (optionally) writes past the end of an allocated block. We plan to do more with this library in the future, including supporting it on Windows, and adding the ability to use the debugging library with your default malloc in addition to using it with tcmalloc. There are also the usual complement of bug fixes, documented in the ChangeLog, and a few minor user-tunable knobs added to components like the system allocator. === 9 June 2009 === I've just released perftools 1.3 Like 1.2, this has a variety of bug fixes, especially related to the Windows build. One of my bugfixes is to undo the weird `ld -r` fix to `.a` files that I introduced in perftools 1.2: it caused problems on too many platforms. I've reverted back to normal `.a` files. To work around the original problem that prompted the `ld -r` fix, I now provide `libtcmalloc_and_profiler.a`, for folks who want to link in both. The most interesting API change is that I now not only override `malloc`/`free`/etc, I also expose them via a unique set of symbols: `tc_malloc`/`tc_free`/etc. This enables clients to write their own memory wrappers that use tcmalloc: {{{ void* malloc(size_t size) { void* r = tc_malloc(size); Log(r); return r; } }}} === 17 April 2009 === I've just released perftools 1.2. This is mostly a bugfix release. The major change is internal: I have a new system for creating packages, which allows me to create 64-bit packages. (I still don't do that for perftools, because there is still no great 64-bit solution, with libunwind still giving problems and --disable-frame-pointers not practical in every environment.) Another interesting change involves Windows: a [http://code.google.com/p/google-perftools/issues/detail?id=126 new patch] allows users to choose to override malloc/free/etc on Windows rather than patching, as is done now. This can be used to create custom CRTs. My fix for this [http://groups.google.com/group/google-perftools/browse_thread/thread/1ff9b50043090d9d/a59210c4206f2060?lnk=gst&q=dynamic#a59210c4206f2060 bug involving static linking] ended up being to make libtcmalloc.a and libperftools.a a big .o file, rather than a true `ar` archive. This should not yield any problems in practice -- in fact, it should be better, since the heap profiler, leak checker, and cpu profiler will now all work even with the static libraries -- but if you find it does, please file a bug report. Finally, the profile_handler_unittest provided in the perftools testsuite (new in this release) is failing on FreeBSD. The end-to-end test that uses the profile-handler is passing, so I suspect the problem may be with the test, not the perftools code itself. However, I do not know enough about how itimers work on FreeBSD to be able to debug it. If you can figure it out, please let me know! === 11 March 2009 === I've just released perftools 1.1! It has many changes since perftools 1.0 including * Faster performance due to dynamically sized thread caches * Better heap-sampling for more realistic profiles * Improved support on Windows (MSVC 7.1 and cygwin) * Better stacktraces in linux (using VDSO) * Many bug fixes and feature requests Note: if you use the CPU-profiler with applications that fork without doing an exec right afterwards, please see the README. Recent testing has shown that profiles are unreliable in that case. The problem has existed since the first release of perftools. We expect to have a fix for perftools 1.2. For more details, see [http://code.google.com/p/google-perftools/issues/detail?id=105 issue 105]. Everyone who uses perftools 1.0 is encouraged to upgrade to perftools 1.1. If you see any problems with the new release, please file a bug report at http://code.google.com/p/google-perftools/issues/list. Enjoy! gperftools-gperftools-2.18/README000066400000000000000000000131661513545575200167150ustar00rootroot00000000000000gperftools ---------- (originally Google Performance Tools) OVERVIEW --------- gperftools is a collection of a high-performance multi-threaded malloc() implementation, plus some pretty nifty performance analysis tools. gperftools is distributed under the terms of the BSD License. Join our mailing list at gperftools@googlegroups.com for updates: https://groups.google.com/forum/#!forum/gperftools gperftools was original home for pprof program. The original pprof was a Perl script and there is not that many Perl experts nowadays. Thankfully, pprof has been rewritten in Go around 2016 and that version of pprof has gotten a lot more feature-ful. So the original pprof is now removed in favor of Go version at https://github.com/google/pprof. Go's own profiling facilities are based on that pprof version as well. TCMALLOC -------- Just link in -ltcmalloc or -ltcmalloc_minimal to get the advantages of tcmalloc -- a replacement for malloc and new. See below for some environment variables you can use with tcmalloc, as well. tcmalloc functionality is available on all systems we've tested; see INSTALL for more details. See README_windows.txt for instructions on using tcmalloc on Windows. HEAP PROFILER ------------- See docs/heapprofile.adoc for information about how to use tcmalloc's heap profiler and analyze its output. As a quick-start, do the following after installing this package: 1) Link your executable with -ltcmalloc 2) Run your executable with the HEAPPROFILE environment var set: $ HEAPPROFILE=/tmp/heapprof [binary args] 3) Run pprof to analyze the heap usage $ pprof /tmp/heapprof.0045.heap # run 'ls' to see options $ pprof --gv /tmp/heapprof.0045.heap You can also use LD_PRELOAD to heap-profile an executable that you didn't compile. There are other environment variables, besides HEAPPROFILE, you can set to adjust the heap-profiler behavior; c.f. "ENVIRONMENT VARIABLES" below. The heap profiler is available on all unix-based systems we've tested; see INSTALL for more details. It is not currently available on Windows. CPU PROFILER ------------ See docs/cpuprofile.adoc for information about how to use the CPU profiler and analyze its output. As a quick-start, do the following after installing this package: 1) Link your executable with -lprofiler 2) Run your executable with the CPUPROFILE environment var set: $ CPUPROFILE=/tmp/prof.out [binary args] 3) Run pprof to analyze the CPU usage $ pprof /tmp/prof.out # -pg-like text output $ pprof --gv /tmp/prof.out # really cool graphical output There are other environment variables, besides CPUPROFILE, you can set to adjust the cpu-profiler behavior; cf "ENVIRONMENT VARIABLES" below. The CPU profiler is available on all unix-based systems we've tested; see INSTALL for more details. It is not currently available on Windows. NOTE: CPU profiling doesn't work after fork (unless you immediately do an exec()-like call afterwards). Furthermore, if you do fork, and the child calls exit(), it may corrupt the profile data. You can use _exit() to work around this. We hope to have a fix for both problems in the next release of perftools (hopefully perftools 1.2). CONFIGURATION OPTIONS --------------------- For advanced users, there are several flags you can pass to './configure' that tweak tcmalloc performance. (These are in addition to the environment variables you can set at runtime to affect tcmalloc, described below.) See the INSTALL file for details. ENVIRONMENT VARIABLES --------------------- The cpu profiler, heap checker, and heap profiler will lie dormant, using no memory or CPU, until you turn them on. (Thus, there's no harm in linking -lprofiler into every application, and also -ltcmalloc assuming you're ok using the non-libc malloc library.) The easiest way to turn them on is by setting the appropriate environment variables. We have several variables that let you enable/disable features as well as tweak parameters. Here are some of the most important variables: HEAPPROFILE=
 -- turns on heap profiling and dumps data using this prefix
HEAPCHECK=  -- turns on heap checking with strictness 'type'
CPUPROFILE= -- turns on cpu profiling and dumps data to this file.
PROFILESELECTED=1 -- if set, cpu-profiler will only profile regions of code
                     surrounded with ProfilerEnable()/ProfilerDisable().
CPUPROFILE_FREQUENCY=x-- how many interrupts/second the cpu-profiler samples.

PERFTOOLS_VERBOSE= -- the higher level, the more messages malloc emits
MALLOCSTATS=    -- prints memory-use stats at program-exit

For a full list of variables, see the documentation pages:
   docs/cpuprofile.adoc
   docs/heapprofile.adoc

See also TCMALLOC_STACKTRACE_METHOD_VERBOSE and
TCMALLOC_STACKTRACE_METHOD environment variables briefly documented in
our INSTALL file and on our wiki page at:
https://github.com/gperftools/gperftools/wiki/gperftools'-stacktrace-capturing-methods-and-their-issues


COMPILING ON NON-LINUX SYSTEMS
------------------------------

Perftools was developed and tested on x86, aarch64 and riscv Linux
systems, and it works in its full generality only on those systems.

However, we've successfully ported much of the tcmalloc library to
FreeBSD, Solaris x86 (not tested recently though), and Mac OS X
(aarch64; x86 and ppc have not been tested recently); and we've ported
the basic functionality in tcmalloc_minimal to Windows.  See INSTALL
for details.  See README_windows.txt for details on the Windows port.


---
Originally written: 17 May 2011
Last refreshed: 10 Aug 2023
gperftools-gperftools-2.18/README_windows.txt000066400000000000000000000106341513545575200213020ustar00rootroot00000000000000--- COMPILING

This project has begun being ported to Windows, only tcmalloc_minimal
is supported at this time.  A working solution file exists in this
directory:
    gperftools.sln

You can load this solution file into Visual Studio 2015 or
later -- in the latter case, it will automatically convert the files
to the latest format for you.

When you build the solution, it will create a number of unittests,
which you can run by hand (or, more easily, under the Visual Studio
debugger) to make sure everything is working properly on your system.
The binaries will end up in a directory called "debug" or "release" in
the top-level directory (next to the .sln file).

I don't know very much about how to install DLLs on Windows, so you'll
have to figure out that part for yourself.  If you choose to just
re-use the existing .sln, make sure you set the IncludeDir's
appropriately!  Look at the properties for libtcmalloc_minimal.dll.

Note that these systems are set to build in Debug mode by default.
You may want to change them to Release mode.

To use tcmalloc_minimal in your own projects, you should only need to
build the dll and install it someplace, so you can link it into
further binaries.  To use the dll, you need to add the following to
the linker line of your executable:
   "libtcmalloc_minimal.lib" /INCLUDE:"__tcmalloc"

Here is how to accomplish this in Visual Studio 2015:

1) Have your executable depend on the tcmalloc library by selecting
   "Project Dependencies..." from the "Project" menu.  Your executable
   should depend on "libtcmalloc_minimal".

2) Have your executable depend on a tcmalloc symbol -- this is
   necessary so the linker doesn't "optimize out" the libtcmalloc
   dependency -- by right-clicking on your executable's project (in
   the solution explorer), selecting Properties from the pull-down
   menu, then selecting "Configuration Properties" -> "Linker" ->
   "Input".  Then, in the "Force Symbol References" field, enter the
   text "__tcmalloc" (without the quotes).  Be sure to do this for both
   debug and release modes!

You can also link tcmalloc code in statically -- see the example
project tcmalloc_minimal_unittest-static, which does this.  For this
to work, you'll need to add "/D PERFTOOLS_DLL_DECL=" to the compile
line of every perftools .cc file.  You do not need to depend on the
tcmalloc symbol in this case (that is, you don't need to do either
step 1 or step 2 from above).

An alternative to all the above is to statically link your application
with libc, and then replace its malloc with tcmalloc.  This allows you
to just build and link your program normally; the tcmalloc support
comes in a post-processing step.  This is more reliable than the above
technique (which depends on run-time patching, which is inherently
fragile), though more work to set up.  For details, see
   https://groups.google.com/group/google-perftools/browse_thread/thread/41cd3710af85e57b


--- THE HEAP-PROFILER

The heap-profiler has had a preliminary port to Windows but does not
build on Windows by default.  It has not been well tested, and
probably does not work at all when Frame Pointer Optimization (FPO) is
enabled -- that is, in release mode.  The other features of perftools,
such as the cpu-profiler and leak-checker, have not yet been ported to
Windows at all.


--- ISSUES

NOTE ON _MSIZE and _RECALLOC: The tcmalloc version of _msize returns
the size of the region tcmalloc allocated for you -- which is at least
as many bytes you asked for, but may be more.  (btw, these *are* bytes
you own, even if you didn't ask for all of them, so it's correct code
to access all of them if you want.)  Unfortunately, the Windows CRT
_recalloc() routine assumes that _msize returns exactly as many bytes
as were requested.  As a result, _recalloc() may not zero out new
bytes correctly.  IT'S SAFEST NOT TO USE _RECALLOC WITH TCMALLOC.
_recalloc() is a tricky routine to use in any case (it's not safe to
use with realloc, for instance).


I have little experience with Windows programming, so there may be
better ways to set this up than I've done!  If you run across any
problems, please post to the google-perftools Google Group, or report
them on the gperftools Google Code site:
   http://groups.google.com/group/google-perftools
   http://code.google.com/p/gperftools/issues/list

-- craig
-- updated by alk on 31 July 2023

Last modified: 31 July 2023
gperftools-gperftools-2.18/autogen.sh000077500000000000000000000000311513545575200200210ustar00rootroot00000000000000#!/bin/sh

autoreconf -i
gperftools-gperftools-2.18/benchmark/000077500000000000000000000000001513545575200177605ustar00rootroot00000000000000gperftools-gperftools-2.18/benchmark/binary_trees.cc000066400000000000000000000054261513545575200227640ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
//
// Copied from
// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=binarytrees&lang=gpp&id=2
// and slightly modified (particularly by adding multi-threaded
// operation to hit malloc harder).
//
// This version of binary trees is mostly new/delete benchmark
//
// NOTE: copyright of this code is unclear, but we only distribute
// source.

/* The Computer Language Benchmarks Game
 * http://benchmarksgame.alioth.debian.org/
 *
 * Contributed by Jon Harrop
 * Modified by Alex Mizrahi
 * Adapted for gperftools and added threads by Aliaksei Kandratsenka
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct Node {
  Node *l, *r;
  int i;
  Node(int i2) : l(0), r(0), i(i2) {}
  Node(Node *l2, int i2, Node *r2) : l(l2), r(r2), i(i2) {}
  ~Node() { delete l; delete r; }
  int check() const {
    if (l) {
      return l->check() + i - r->check();
    } else {
      return i;
    }
  }
};

Node *make(int i, int d) {
  if (d == 0) return new Node(i);
  return new Node(make(2*i-1, d-1), i, make(2*i, d-1));
}

void run(int given_depth) {
  int min_depth = 4,
    max_depth = std::max(min_depth+2,
			 given_depth),
    stretch_depth = max_depth+1;

  {
    Node *c = make(0, stretch_depth);
    std::cout << "stretch tree of depth " << stretch_depth << "\t "
      << "check: " << c->check() << std::endl;
    delete c;
  }

  Node *long_lived_tree=make(0, max_depth);

  for (int d=min_depth; d<=max_depth; d+=2) {
    int iterations = 1 << (max_depth - d + min_depth), c=0;
    for (int i=1; i<=iterations; ++i) {
      Node *a = make(i, d), *b = make(-i, d);
      c += a->check() + b->check();
      delete a;
      delete b;
    }
    std::cout << (2*iterations) << "\t trees of depth " << d << "\t "
	      << "check: " << c << std::endl;
  }

  std::cout << "long lived tree of depth " << max_depth << "\t "
	    << "check: " << (long_lived_tree->check()) << "\n";

  delete long_lived_tree;
}

static void *run_tramp(void *_a) {
  intptr_t a = reinterpret_cast(_a);
  run(a);
  return 0;
}

int main(int argc, char *argv[]) {
  int given_depth = argc >= 2 ? atoi(argv[1]) : 20;
  int thread_count = std::max(1, argc >= 3 ? atoi(argv[2]) : 1) - 1;
  std::vector threads(thread_count);

  for (int i = 0; i < thread_count; i++) {
    int rv = pthread_create(&threads[i], nullptr,
                            run_tramp,
                            reinterpret_cast(given_depth));
    if (rv) {
      errno = rv;
      perror("pthread_create");
    }
  }
  run_tramp(reinterpret_cast(given_depth));
  for (int i = 0; i < thread_count; i++) {
    pthread_join(threads[i], nullptr);
  }
  return 0;
}
gperftools-gperftools-2.18/benchmark/malloc_bench.cc000066400000000000000000000242761513545575200227100ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

#include "run_benchmark.h"

static void bench_fastpath_throughput(long iterations,
                                      uintptr_t param)
{
  size_t sz = 32;
  for (; iterations>0; iterations--) {
    void *p = (operator new)(sz);
    (operator delete)(p);
    // this makes next iteration use different free list. So
    // subsequent iterations may actually overlap in time.
    sz = ((sz * 8191) & 511) + 16;
  }
}

static void bench_fastpath_dependent(long iterations,
                                     uintptr_t param)
{
  size_t sz = 32;
  for (; iterations>0; iterations--) {
    uintptr_t p = reinterpret_cast((operator new)(sz));
    // casts are because gcc doesn't like us using p's value after it
    // is freed.
    (operator delete)(reinterpret_cast(p));

    // this makes next iteration depend on current iteration. But this
    // iteration's free may still overlap with next iteration's malloc
    sz = ((sz | static_cast(p)) & 511) + 16;
  }
}

static void bench_fastpath_simple(long iterations,
                                  uintptr_t param)
{
  size_t sz = static_cast(param);
  for (; iterations>0; iterations--) {
    void *p = (operator new)(sz);
    (operator delete)(p);
    // next iteration will use same free list as this iteration. So it
    // should be prevent next iterations malloc to go too far before
    // free done. But using same size will make free "too fast" since
    // we'll hit size class cache.
  }
}

#if __cpp_sized_deallocation
static void bench_fastpath_simple_sized(long iterations,
                                        uintptr_t param)
{
  size_t sz = static_cast(param);
  for (; iterations>0; iterations--) {
    void *p = (operator new)(sz);
    (operator delete)(p, sz);
    // next iteration will use same free list as this iteration. So it
    // should be prevent next iterations malloc to go too far before
    // free done. But using same size will make free "too fast" since
    // we'll hit size class cache.
  }
}
#endif  // __cpp_sized_deallocation

#if __cpp_aligned_new
static void bench_fastpath_memalign(long iterations,
                                    uintptr_t param)
{
  size_t sz = static_cast(param);
  for (; iterations>0; iterations--) {
    static constexpr std::align_val_t kAlign{32};
    void *p = (operator new)(sz, kAlign);
    (operator delete)(p, sz, kAlign);
    // next iteration will use same free list as this iteration. So it
    // should be prevent next iterations malloc to go too far before
    // free done. But using same size will make free "too fast" since
    // we'll hit size class cache.
  }
}
#endif  // __cpp_aligned_new

static void bench_fastpath_stack(long iterations,
                                 uintptr_t _param)
{

  size_t sz = 64;
  long param = static_cast(_param);
  param = std::max(1l, param);
  std::unique_ptr stack = std::make_unique(param);
  for (; iterations>0; iterations -= param) {
    for (long k = param-1; k >= 0; k--) {
      void *p = (operator new)(sz);
      stack[k] = p;
      // this makes next iteration depend on result of this iteration
      sz = ((sz | reinterpret_cast(p)) & 511) + 16;
    }
    for (long k = 0; k < param; k++) {
      (operator delete)(stack[k]);
    }
  }
}

static void bench_fastpath_stack_simple(long iterations,
                                        uintptr_t _param)
{

  size_t sz = 32;
  long param = static_cast(_param);
  param = std::max(1l, param);
  std::unique_ptr stack = std::make_unique(param);
  for (; iterations>0; iterations -= param) {
    for (long k = param-1; k >= 0; k--) {
      void *p = (operator new)(sz);
      stack[k] = p;
    }
    for (long k = 0; k < param; k++) {
#if __cpp_sized_deallocation
      (operator delete)(stack[k], sz);
#else
      (operator delete)(stack[k]);
#endif
    }
  }
}

static void bench_fastpath_rnd_dependent(long iterations,
                                         uintptr_t _param)
{
  static const uintptr_t rnd_c = 1013904223;
  static const uintptr_t rnd_a = 1664525;

  size_t sz = 128;
  if ((_param & (_param - 1))) {
    abort();
  }

  long param = static_cast(_param);
  param = std::max(1l, param);
  std::unique_ptr ptrs = std::make_unique(param);

  for (; iterations>0; iterations -= param) {
    for (int k = param-1; k >= 0; k--) {
      void *p = (operator new)(sz);
      ptrs[k] = p;
      sz = ((sz | reinterpret_cast(p)) & 511) + 16;
    }

    // this will iterate through all objects in order that is
    // unpredictable to processor's prefetchers
    uint32_t rnd = 0;
    uint32_t free_idx = 0;
    do {
      (operator delete)(ptrs[free_idx]);
      rnd = rnd * rnd_a + rnd_c;
      free_idx = rnd & (param - 1);
    } while (free_idx != 0);
  }
}

static void bench_fastpath_rnd_dependent_8cores(long iterations,
                                                uintptr_t _param)
{
  static const uintptr_t rnd_c = 1013904223;
  static const uintptr_t rnd_a = 1664525;

  if ((_param & (_param - 1))) {
    abort();
  }

  long param = static_cast(_param);
  param = std::max(1l, param);

  auto body = [iterations, param] () {
    size_t sz = 128;
    std::unique_ptr ptrs = std::make_unique(param);

    for (long i = iterations; i>0; i -= param) {
      for (int k = param-1; k >= 0; k--) {
        void *p = (operator new)(sz);
        ptrs[k] = p;
        sz = ((sz | reinterpret_cast(p)) & 511) + 16;
      }

      // this will iterate through all objects in order that is
      // unpredictable to processor's prefetchers
      uint32_t rnd = 0;
      uint32_t free_idx = 0;
      do {
        (operator delete)(ptrs[free_idx]);
        rnd = rnd * rnd_a + rnd_c;
        free_idx = rnd & (param - 1);
      } while (free_idx != 0);
    }
  };

  std::thread ts[] = {
    std::thread{body}, std::thread{body}, std::thread{body}, std::thread{body},
    std::thread{body}, std::thread{body}, std::thread{body}, std::thread{body}};
  for (auto &t : ts) {
    t.join();
  }
}

void randomize_one_size_class(size_t size) {
  size_t count = (100<<20) / size;
  auto randomize_buffer = std::make_unique(count);

  for (size_t i = 0; i < count; i++) {
    randomize_buffer[i] = (operator new)(size);
  }

  std::shuffle(randomize_buffer.get(), randomize_buffer.get() + count, std::minstd_rand(rand()));

  for (size_t i = 0; i < count; i++) {
    (operator delete)(randomize_buffer[i]);
  }
}

void randomize_size_classes() {
  randomize_one_size_class(8);
  int i;
  for (i = 16; i < 256; i += 16) {
    randomize_one_size_class(i);
  }
  for (; i < 512; i += 32) {
    randomize_one_size_class(i);
  }
  for (; i < 1024; i += 64) {
    randomize_one_size_class(i);
  }
  for (; i < (4 << 10); i += 128) {
    randomize_one_size_class(i);
  }
  for (; i < (32 << 10); i += 1024) {
    randomize_one_size_class(i);
  }
}

int main(int argc, char **argv)
{
  init_benchmark(&argc, &argv);

  if (!benchmark_list_only) {
    printf("Trying to randomize freelists..."); fflush(stdout);
    randomize_size_classes();
    printf("done.\n");
  }

  report_benchmark("bench_fastpath_throughput", bench_fastpath_throughput, 0);
  report_benchmark("bench_fastpath_dependent", bench_fastpath_dependent, 0);
  report_benchmark("bench_fastpath_simple", bench_fastpath_simple, 64);
  report_benchmark("bench_fastpath_simple", bench_fastpath_simple, 2048);
  report_benchmark("bench_fastpath_simple", bench_fastpath_simple, 16384);

#if __cpp_sized_deallocation
  report_benchmark("bench_fastpath_simple_sized", bench_fastpath_simple_sized, 64);
  report_benchmark("bench_fastpath_simple_sized", bench_fastpath_simple_sized, 2048);
#endif

#if __cpp_aligned_new
  report_benchmark("bench_fastpath_memalign", bench_fastpath_memalign, 64);
  report_benchmark("bench_fastpath_memalign", bench_fastpath_memalign, 2048);
#endif

  for (int i = 8; i <= 512; i <<= 1) {
    report_benchmark("bench_fastpath_stack", bench_fastpath_stack, i);
  }

  report_benchmark("bench_fastpath_stack_simple", bench_fastpath_stack_simple, 32);
  report_benchmark("bench_fastpath_stack_simple", bench_fastpath_stack_simple, 8192);
  report_benchmark("bench_fastpath_stack_simple", bench_fastpath_stack_simple, 32768);

  report_benchmark("bench_fastpath_rnd_dependent", bench_fastpath_rnd_dependent, 32);
  report_benchmark("bench_fastpath_rnd_dependent", bench_fastpath_rnd_dependent, 8192);
  report_benchmark("bench_fastpath_rnd_dependent", bench_fastpath_rnd_dependent, 32768);

  report_benchmark("bench_fastpath_rnd_dependent_8cores", bench_fastpath_rnd_dependent_8cores, 32768);

  return 0;
}
gperftools-gperftools-2.18/benchmark/run_benchmark.cc000066400000000000000000000167241513545575200231170ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "config.h"

#include "run_benchmark.h"

#include "trivialre.h"

#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 

#ifndef _WIN32
#include 
#endif

static constexpr double kTrialNSec = 0.3e9;

static double benchmark_duration_nsec = 3e9;
static int benchmark_repetitions = 3;
static std::function benchmark_filter;
bool benchmark_list_only;

static
std::function parse_filter_or_die(std::string_view filter) {
  struct Policy {
    bool failed{};
    std::string_view msg{};
    std::string_view at{};

    void NoteError(std::string_view msg, std::string_view at) {
      failed = true;
      this->msg = msg;
      this->at = at;
    }
    void StartedParsing(std::string_view str) {}
  };

  trivialre::re_compiler::C compiler({});
  trivialre::Matcher matcher = compiler.CompileOrDie(filter);
  if (compiler.failed) {
    fprintf(stderr, "failed to parse benchmark filter: '%.*s'.\nParse error: %.*s at %.*s\n",
            (int)filter.size(), filter.data(),
            (int)compiler.msg.size(), compiler.msg.data(),
            (int)compiler.at.size(), compiler.at.data());
    exit(1);
  }

  return [matcher] (std::string_view candidate) {
    return trivialre::MatchSubstring(matcher, candidate);
  };
}

void init_benchmark(int *argc, char ***argv) {
  int n = *argc;
  char **args = *argv;
  for (int i = 1; i < n; i++) {
    std::string_view a{args[i]};
    if (a.substr(0, 2) != "--") {
      fprintf(stderr, "benchmark only understands --long-form= flags. got: %.*s\n",
              (int)a.size(), a.data());
      exit(1);
    }
    a.remove_prefix(2);
    std::string_view rest;
    auto has_prefix = [&] (std::string_view s) {
      bool rv = (a.substr(0, s.size()) == s);
      if (rv) {
        rest = a.substr(s.size());
      }
      return rv;
    };
    if (a == "help") {
      printf("%s --help\n"
             "  --benchmark_filter=\n"
             "  --benchmark_list\n"
             "  --benchmark_min_time=\n"
             "  --benchmark_repetitions=\n"
             "\n", (*argv)[0]);
      benchmark_list_only = true;
    } else if (has_prefix("benchmark_min_time=")) {
      char *end = nullptr;
      double value = strtod(rest.data(), &end);
      if (!end || *end) {
        fprintf(stderr, "failed to parse benchmark_min_time argument: %s\n", args[i]);
        exit(1);
      }
      benchmark_duration_nsec = value * 1e9;
      // printf("benchmark_duration_nsec = %f\n", benchmark_duration_nsec);
    } else if (has_prefix("benchmark_repetitions=")) {
      char *end = nullptr;
      long value = strtol(rest.data(), &end, 0);
      if (!end || *end || value < 1 || static_cast(static_cast(value)) != value) {
        fprintf(stderr, "failed to parse benchmark_repetitions argument: %s\n", args[i]);
        exit(1);
      }
      benchmark_repetitions = value;
    } else if (has_prefix("benchmark_filter=")) {
      benchmark_filter = parse_filter_or_die(rest);
    } else if (a == "benchmark_list") {
      benchmark_list_only = true;
    } else {
      fprintf(stderr, "unknown flag: %.*s\n", (int)a.size(), a.data());
      exit(1);
    }
  }
}

struct internal_bench {
  bench_body body;
  uintptr_t param;
};

static void run_body(struct internal_bench *b, long iterations)
{
  b->body(iterations, b->param);
}

#ifdef _WIN32
static uint64_t get_fs_time_ticks()
{
  FILETIME ft;
  GetSystemTimePreciseAsFileTime(&ft);
  return (uint64_t{ft.dwHighDateTime} << 32) + ft.dwLowDateTime;
}

static double measure_once(struct internal_bench *b, long iterations)
{
  uint64_t ticks_before, ticks_after;

  ticks_before = get_fs_time_ticks();

  run_body(b, iterations);

  ticks_after = get_fs_time_ticks();

  // Windows FILETIME ticks are 100 nanos per tick.
  return (ticks_after - ticks_before) * 100e0;
}
#else
static double measure_once(struct internal_bench *b, long iterations)
{
  struct timeval tv_before, tv_after;
  int rv;
  double time;

  rv = gettimeofday(&tv_before, nullptr);
  if (rv) {
    perror("gettimeofday");
    abort();
  }

  run_body(b, iterations);

  rv = gettimeofday(&tv_after, nullptr);
  if (rv) {
    perror("gettimeofday");
    abort();
  }
  tv_after.tv_sec -= tv_before.tv_sec;
  time = tv_after.tv_sec * 1E6 + tv_after.tv_usec;
  time -= tv_before.tv_usec;
  time *= 1000;
  return time;
}
#endif

static double run_benchmark(struct internal_bench *b)
{
  long iterations = 128;
  double nsec;
  while (1) {
    nsec = measure_once(b, iterations);
    if (nsec > kTrialNSec) {
      break;
    }
    iterations = ((unsigned long)iterations) << 1;
    if (iterations <= 0) { // overflow
      abort();
    }
  }
  while (nsec < benchmark_duration_nsec) {
    double target_iterations = iterations * benchmark_duration_nsec * 1.1 / nsec;
    if (target_iterations > (double)LONG_MAX) {
      abort();
    }
    iterations = target_iterations;
    nsec = measure_once(b, iterations);
  }
  return nsec / iterations;
}

void report_benchmark(const char *name, bench_body body, uintptr_t param)
{
  std::ostringstream full_name_stream(name, std::ios_base::ate);
  if (param) {
    full_name_stream << "(" << param << ")";
  }
  std::string full_name = full_name_stream.str();

  if (benchmark_list_only) {
    printf("known benchmark: %s\n", full_name.c_str());
    return;
  }

  if (benchmark_filter && !benchmark_filter(std::string_view{full_name})) {
    return;
  }

  internal_bench b;
  b.body = body;
  b.param = param;
  for (int i = 0; i < benchmark_repetitions; i++) {
    int slen = printf("Benchmark: %s", full_name.c_str());
    fflush(stdout);

    double nsec = run_benchmark(&b);
    int padding_size;

    padding_size = 60 - slen;
    if (padding_size < 1) {
      padding_size = 1;
    }
    printf("%*c%f nsec (rate: %f Mops/sec)\n", padding_size, ' ', nsec, 1e9/nsec/1e6);
    fflush(stdout);
  }
}
gperftools-gperftools-2.18/benchmark/run_benchmark.h000066400000000000000000000036531513545575200227560ustar00rootroot00000000000000// -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef _RUN_BENCHMARK_H_
#define _RUN_BENCHMARK_H_
#include 

#ifdef __cplusplus
extern "C" {
#endif

void init_benchmark(int *argc, char ***argv);

extern bool benchmark_list_only;

typedef void (*bench_body)(long iterations, uintptr_t param);

void report_benchmark(const char *name, bench_body body, uintptr_t param);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // _RUN_BENCHMARK_H_
gperftools-gperftools-2.18/benchmark/trivialre.h000066400000000000000000000352631513545575200221430ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef TRIVIALRE_H_
#define TRIVIALRE_H_

#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace trivialre {

// Callback for Matcher. See below.
using CB = std::function;
// Matcher is a function that gets string and invokes given callback
// with remaining text (i.e. suffix of parsed part) for each
// successful parsing. We're able to express arbitrary trees of regexp
// expressions with this simple abstraction.
using Matcher = std::function;

// MatchSubstring returns true iff there is substring of `str' that
// matches given matcher.
inline bool MatchSubstring(const Matcher& m, std::string_view str) {
  size_t sz = str.size();
  CB succeed = [](std::string_view str, bool line_start) { return true; };
  bool line_start = true;
  for (size_t i = 0; i < sz; i++) {
    if (m(str, line_start, succeed)) {
      return true;
    }
    line_start = (str[0] == '\n');
    str.remove_prefix(1);
  }
  return m("", line_start, succeed);
}

Matcher CompileREOrDie(std::string_view str);

// --- implementation ---

namespace matchers {

// MatcherBuilder is a collection of functions that combine Matchers
// according to various kinds of regex structures (sequence,
// alternatives, '*' etc).
struct MatcherBuilder {
  using Matcher = trivialre::Matcher;

  // Returns Matcher that parses given literal.
  static Matcher Lit(std::string_view lit);
  // Returns Matcher that left then right.
  static Matcher Seq(Matcher left, Matcher right);
  // Returns Matcher that given parses given sequence of matchers
  // (folding from right for efficiency).
  static Matcher SeqMany(std::initializer_list list);
  // Returns Matcher that parses either left or right.
  static Matcher Alt(Matcher left, Matcher right);
  // Returns Matcher that matches 0 or more parsings of given nested
  // matcher. I.e. implements '*' operator of regexps.
  static Matcher Star(Matcher nested);
  static Matcher LineStart();
  static Matcher LineEnd();

  // Returns Matcher that parses one character iff pred(character) is
  // true.
  template 
  static Matcher CharP(Predicate pred);

  // Dot matcher implements '.' operator of regexps. I.e. matches
  // exactly one non-newline character.
  static Matcher Dot() {
    return CharP([](char ch) { return ch != '\n'; });
  }
  // Any matcher immediately suceeds consuming no text at all.
  static Matcher Any() {
    return [](std::string_view str, bool line_start, const CB& cb) { return cb(str, line_start); };
  }
};

inline Matcher MatcherBuilder::Lit(std::string_view lit) {
  return [=](std::string_view str, bool line_start, const CB& cb) -> bool {
    auto sz = lit.size();
    if (str.substr(0, sz) != lit) {
      return false;
    }
    line_start = (sz == 0) ? line_start : (str[sz - 1] == '\n');
    str.remove_prefix(sz);
    // printf("Matched prefix %.*s (rest: %.*s)\n",
    //        static_cast(lit.size()), lit.data(),
    //        std::max(str.size(), 6), str.data());
    return cb(str, line_start);
  };
}

inline Matcher MatcherBuilder::Seq(Matcher left, Matcher right) {
  return [left = std::move(left), right = std::move(right)](std::string_view str, bool line_start, const CB& cb) -> bool {
    return left(str, line_start, [=](std::string_view str, bool line_start) { return right(str, line_start, cb); });
  };
}

inline Matcher MatcherBuilder::SeqMany(std::initializer_list list) {
  if (std::empty(list)) {
    return Any();
  }
  auto it = std::rbegin(list);
  Matcher rv = *it++;
  while (it != std::rend(list)) {
    rv = Seq(*it++, std::move(rv));
  }
  return rv;
}

inline Matcher MatcherBuilder::Alt(Matcher left, Matcher right) {
  return [left = std::move(left), right = std::move(right)](std::string_view str, bool line_start, const CB& cb) -> bool {
    if (left(str, line_start, cb)) {
      return true;
    }
    return right(str, line_start, cb);
  };
}

inline Matcher MatcherBuilder::Star(Matcher nested) {
  return [nested = std::move(nested)](std::string_view str, bool line_start, const CB& cb) -> bool {
    CB rec;
    rec = [&](std::string_view str, bool line_start) -> bool {
      if (cb(str, line_start)) {
        return true;
      }
      return nested(str, line_start, rec);
    };
    return rec(str, line_start);
  };
}

template 
Matcher MatcherBuilder::CharP(Predicate pred) {
  return [pred = std::move(pred)](std::string_view str, bool line_start, const CB& cb) -> bool {
    if (str.size() && pred(str[0])) {
      bool line_start = (str[0] == '\n');
      str.remove_prefix(1);
      return cb(str, line_start);
    }
    return false;
  };
}

inline Matcher MatcherBuilder::LineStart() {
  return [](std::string_view str, bool line_start, const CB& cb) {
    if (!line_start) return false;
    return cb(str, line_start);
  };
}

inline Matcher MatcherBuilder::LineEnd() {
  return [](std::string_view str, bool line_start, const CB& cb) {
    if (str.size() && str[0] != '\n') {
      return false;
    }
    // Yes, line-end doesn't consume the \n character.
    return cb(str, line_start);
  };
}

}  // namespace matchers

namespace re_compiler {

struct ErrorPolicy {
  std::string_view original_str;

  void NoteError(std::string_view msg, std::string_view at) {
    // For our trivial implementation we're only able to crash
    fprintf(stderr, "parse error %.*s, at: %.*s\n", int(msg.size()), msg.data(), int(at.size()), at.data());
    fprintf(stderr, "expression we were parsing:\n%.*s\n", int(original_str.size()), original_str.data());
    if (size_t diff = at.data() - original_str.data(); diff < 120) {
      fprintf(stderr, "%s^\n", std::string{}.append(diff, '-').c_str());
    }
    fflush(stderr);
    abort();
  }

  void StartedParsing(std::string_view str) { original_str = str; }
};

// C is our regexp compiler. It assembles matcher tree from string
// regexp representation. Given builder is used to construct concrete
// matchers, allowing flexibility (see StringTestingBuilder).
template 
struct C : public ErrorPolicy {
  using Matcher = typename Builder::Matcher;
  // ParseResult is Matcher (or nothing if we parsed empty string) and
  // remaining text.
  using ParseResult = std::pair, std::string_view>;

  const Builder& builder;
  explicit C(const Builder& builder) : builder(builder) {}

  bool IsCharAt(std::string_view str, size_t index, char ch) { return index < str.size() && str[index] == ch; }

  // This is top level parser. It parses alternatives of regex runs.
  ParseResult ParseAlt(std::string_view str) {
    auto [maybe_left, str_l] = ParseRun(str);
    if (IsCharAt(str_l, 0, '|')) {
      if (!maybe_left) {
        maybe_left.emplace(builder.Any());
      }
      auto [maybe_right, str_r] = ParseAlt(str_l.substr(1));
      if (!maybe_right) {
        maybe_right.emplace(builder.Any());
      }
      return {builder.Alt(std::move(maybe_left.value()), std::move(maybe_right.value())), str_r};
    }
    return {std::move(maybe_left), str_l};
  }

  using FnPred = std::function;
  template 
  void AddPred(FnPred* pred, Body body) {
    if (!*pred) {
      *pred = body;
    } else {
      *pred = [old = std::move(*pred), body = std::move(body)](char ch) { return old(ch) || body(ch); };
    }
  }

  // Parses [] expression. Note: str is just past
  // opening '[' character)
  ParseResult CompileCharSet(std::string_view str) {
    bool negated = false;
    if (IsCharAt(str, 0, '^')) {
      negated = true;
      str.remove_prefix(1);
    }
    FnPred pred;

    while (str.size() > 0 && str[0] != ']') {
      if (str.size() > 2 && str[1] == '-' && str[2] != ']') {
        // range
        AddPred(&pred, [a = str[0], b = str[2]](char ch) { return a <= ch && ch <= b; });
        str.remove_prefix(3);
        continue;
      }

      char ch = str[0];

      if (ch == '\\') {
        if (str.size() == 1) {
          break;
        }
        str.remove_prefix(1);
        ch = str[0];
      }

      AddPred(&pred, [ch](char candidate) { return ch == candidate; });

      str.remove_prefix(1);
    }

    if (!IsCharAt(str, 0, ']')) {
      ErrorPolicy::NoteError("failed to spot ] at the end of char-set term", str);
      return {{}, ""};
    }

    if (!pred) {
      pred = [negated](char candidate) { return negated; };
    } else if (negated) {
      pred = [pred = std::move(pred)](char candidate) { return !pred(candidate); };
    }
    return {builder.CharP(std::move(pred)), str.substr(1)};
  }

  // Parses sequence of literals and groups and groups of '*' and '+'
  // expressions.
  ParseResult ParseRun(std::string_view str) {
    if (str.size() == 0) {
      return {{}, str};
    }

    static constexpr char kSpecials[] = "()[]{}.*|\\?+^$";
    static constexpr const char* kSpecialsEnd = kSpecials + sizeof(kSpecials) - 1;

    size_t i;
    for (i = 0; i < str.size(); i++) {
      char ch = str[i];
      if (std::find(kSpecials, kSpecialsEnd, ch) != kSpecialsEnd) {
        break;
      }
    }

    if (i) {
      // we got literal
      if (i > 1 && (IsCharAt(str, i, '*') || IsCharAt(str, i, '+') || IsCharAt(str, i, '?'))) {
        // only last char of literal char runs will be '*'-ed. So lets
        // be careful
        i--;
      }
      // we got literal. Lets try to concat it with possible '*' and next run
      return MaybeStar(builder.Lit(str.substr(0, i)), str.substr(i));
    }

    char first = str[0];
    if (first == '\\' && str.size() > 1) {
      std::string_view literal;
      if (str[1] == 'n') {
        literal = "\n";
      } else if (str[1] == 't') {
        literal = "\t";
      } else if (str[1] == ' ') {
        literal = " ";
      } else if (auto place = std::find(kSpecials, kSpecialsEnd, str[1]); place != kSpecialsEnd) {
        literal = {place, 1};
      } else {
        // Failure to parse
        return {{}, str};
      }
      return MaybeStar(builder.Lit(literal), str.substr(2));
    }
    if (first == '^') {
      return MaybeStar(builder.LineStart(), str.substr(1));
    }
    if (first == '$') {
      return MaybeStar(builder.LineEnd(), str.substr(1));
    }
    if (first == '.') {
      return MaybeStar(builder.Dot(), str.substr(1));
    }
    if (first == '[') {
      return CompileCharSet(str.substr(1));
    }

    if (first == '(') {
      auto [maybe_nested, new_str] = ParseAlt(str.substr(1));

      if (!IsCharAt(new_str, 0, ')')) {
        ErrorPolicy::NoteError("failed to spot ) at the end of group term", new_str);
        return {{}, ""};
      }

      if (maybe_nested) {
        return MaybeStar(std::move(maybe_nested.value()), new_str.substr(1));
      }

      // empty group. We just ignore it. But lets also handle possible
      // '*' after it (which we also eat)
      if (IsCharAt(new_str, 1, '*')) {
        new_str.remove_prefix(1);
      }
      return ParseRun(new_str.substr(1));
    }

    // Likely '|', ')' or parse error
    return {{}, str};
  }

  // Sequences left then right or just left if right is missing).
  Matcher MaybeSeq(Matcher left, std::optional right) {
    if (right) {
      return builder.Seq(std::move(left), std::move(right.value()));
    }
    return left;
  }

  // Builds matcher for '+' expression.
  Matcher MakePlus(Matcher nested) { return builder.Seq(nested, builder.Star(nested)); }

  // Given regex matcher, check if it is followed by '*' or '+' and
  // wrap it if needed, then continue gathering sequence of matches
  // (see ParseRun)
  ParseResult MaybeStar(Matcher left, std::string_view str) {
    if (IsCharAt(str, 0, '*')) {
      left = builder.Star(std::move(left));
      str.remove_prefix(1);
      if (IsCharAt(str, 0, '?')) {
        // We don't produce actual matching, so there is not
        // difference between lazy and eager matching. But lets
        // support the syntax anyways, by ignoring lazyness marker
        str.remove_prefix(1);
      }
    }
    if (IsCharAt(str, 0, '+')) {
      left = MakePlus(std::move(left));
      str.remove_prefix(1);
      if (IsCharAt(str, 0, '?')) {
        // We don't produce actual matching, so there is not
        // difference between lazy and eager matching. But lets
        // support the syntax anyways, by ignoring lazyness marker
        str.remove_prefix(1);
      }
    }
    if (IsCharAt(str, 0, '?')) {
      left = builder.Alt(builder.Any(), std::move(left));
      str.remove_prefix(1);
    }
    auto [maybe_right, new_str] = ParseRun(str);
    return {MaybeSeq(left, std::move(maybe_right)), new_str};
  }

  Matcher CompileOrDie(std::string_view str) {
    ErrorPolicy::StartedParsing(str);
    auto [maybe_m, new_str] = ParseAlt(str);
    if (!new_str.empty()) {
      ErrorPolicy::NoteError("failed to parse entire re string", new_str);
    }
    if (!maybe_m) {
      return builder.Any();
    }
    return maybe_m.value();
  }
};

}  // namespace re_compiler

inline Matcher CompileREOrDie(std::string_view str) { return re_compiler::C({}).CompileOrDie(str); }

}  // namespace trivialre

#endif  // TRIVIALRE_H_
gperftools-gperftools-2.18/benchmark/trivialre_test.cc000066400000000000000000000160361513545575200233350ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "trivialre.h"

#include 

#include 

#include 

using trivialre::CompileREOrDie;
using trivialre::Matcher;
using trivialre::MatchSubstring;

// This is matcher builder that build diagnostic string representation
// of regexp matcher expression tree.
struct StringTestingBuilder {
  using Matcher = std::string;

  static Matcher Lit(std::string_view lit) { return std::string("'") + std::string(lit) + "'"; }
  static Matcher Seq(Matcher left, Matcher right) {
    if (right.substr(0, 5) == "(seq ") {
      right = right.substr(5, right.size() - 1 - 5);
    }
    return std::string("(seq ") + left + " " + right + ")";
  }
  static Matcher Alt(Matcher left, Matcher right) {
    if (right.substr(0, 5) == "(alt ") {
      right = right.substr(5, right.size() - 1 - 5);
    }
    return std::string("(alt ") + left + " " + right + ")";
  }
  static Matcher Star(Matcher nested) { return std::string("(star ") + nested + ")"; }
  static Matcher LineStart() { return "^"; }
  static Matcher LineEnd() { return "$"; }

  template 
  static Matcher CharP(Predicate pred) {
    return "";
  }

  static Matcher Dot() { return ""; }
  static Matcher Any() { return ""; }
};

TEST(TrivialRETest, ConstructedMatchers) {
  using B = trivialre::matchers::MatcherBuilder;
  auto m = B::SeqMany({B::Lit("mismatch"), B::Star(B::Dot()), B::Lit("being dealloc"), B::Star(B::Dot()), B::Lit("free")});

  EXPECT_TRUE(MatchSubstring(m, "crap-mismatch-sd-being dealloc-sd-free-junk"));
  EXPECT_FALSE(MatchSubstring(m, "crap-mismatch-sd-being dealloc-sd-fee-junk"));
}

TEST(TrivialRETest, Minimal) {
  auto m = CompileREOrDie("mismatch.*being dealloc.*free");
  EXPECT_TRUE(MatchSubstring(m, "crap-mismatch-sd-being dealloc-sd-free-junk"));
  EXPECT_FALSE(MatchSubstring(m, "crap-mismatch-sd-being dealloc-sd-fee-junk"));
}

TEST(TrivialRETest, Compilations) {
  // format is {regex, golden-parsing}
  std::vector> cases = {
      {"mis.*being deal.*free", "(seq 'mis' (star ) 'being deal' (star ) 'free')"},
      {"mis.*(being|deal).*free", "(seq 'mis' (star ) (alt 'being' 'deal') (star ) 'free')"},
      {"mis.*(being|deal)*fre*e", "(seq 'mis' (star ) (star (alt 'being' 'deal')) 'fr' (star 'e') 'e')"},
      {"mis.*(being|deal)+?free", "(seq 'mis' (star ) (seq (alt 'being' 'deal') (star (alt 'being' 'deal'))) 'free')"},
      {"mis.*(being|deal)?fre*e", "(seq 'mis' (star ) (alt  'being' 'deal') 'fr' (star 'e') 'e')"},
      {"mis.*being|deal.*free",
       "(alt (seq 'mis' (star ) 'being') (seq 'deal' (star ) "
       "'free'))"},
      {"mis.*?being|deal.*free", "(alt (seq 'mis' (star ) 'being') (seq 'deal' (star ) 'free'))"},
      {"\\*", "'*'"},
      {"\\|", "'|'"},
      {"|", "(alt  )"},
      {"(|)|", "(alt (alt  ) )"},
  };

  printf("--- test cases ---\n");
  for (auto [re, expected] : cases) {
    std::string got = trivialre::re_compiler::C{StringTestingBuilder{}}.CompileOrDie(re);
    printf("test: /%.*s/ -> %s\n", int(re.size()), re.data(), got.c_str());
    EXPECT_EQ(expected, got) << "re: " << re;
  }
}

bool CompilationFails(std::string_view str) {
  struct Policy {
    bool failed{};
    void NoteError(std::string_view msg, std::string_view at) { failed = true; }
    void StartedParsing(std::string_view str) {}
  };
  trivialre::re_compiler::C compiler({});
  std::string result = compiler.CompileOrDie(str);
  printf("for failing: %s -> %s\n", std::string(str).c_str(), std::string(result).c_str());
  return compiler.failed;
}

TEST(TrivialRETest, CompileFailings) {
  std::vector examples = {"[", "(", "{}", "((", "\\A", "\\b", "\\S", "\\s", "\\w"};
  for (auto s : examples) {
    EXPECT_TRUE(CompilationFails(s)) << "s: " << s;
  }
}

TEST(TrivialRETest, Runnings) {
  // Format is {re, example...}. Each example is prefixed with '+' for
  // must match or '-' for must not.
  std::vector> cases2 = {
      {"a*", "+a", "+", "+not"},
      {"aa*", "+a", "+aaa", "+ba", "-b"},
      {"a+", "+a", "+aa", "+aaa", "-", "-b"},
      {".", "-\n", "+a", "-"},

      {"[a-f]", "+a", "-z", "-", "+f", "--"},
      {"[a-f-]", "+a", "-z", "-", "+f", "+-"},
      {"[az]", "+a", "-b", "+z"},
      {"[^a-f]", "-a", "+z", "-", "-f"},
      {"[^a-f-]", "-a", "+z", "-", "-f", "--"},
      {"[a-f0-9]", "+a", "-z", "+0", "+9"},
      {"[^]", "+a", "+\n"},
      {"", "+", "+asdasd"},

      {"a(b|c+)d", "+abd", "-ab", "-abcd", "+accd", "-ad"},
      {"a(b|c+)?d", "+abd", "-ab", "-abcd", "+accd", "+ad"},

      {"^a", "+a", "-ba", "+b\na"},
      {"a$", "+a\nb", "+ba", "+b\na"},
      {"a$\\nb", "+a\nb"},
      {"$", "+", "+aaa"},
      {"^$", "+", "-aaa", "+aaa\n"},
  };

  for (const auto& vec : cases2) {
    Matcher m = CompileREOrDie(vec[0]);
    printf("testing /%s/ re: %s\n", std::string(vec[0]).c_str(),
           trivialre::re_compiler::C({}).CompileOrDie(vec[0])
               .c_str());
    for (size_t i = 1; i < vec.size(); i++) {
      std::string_view s = vec[i];
      printf("trying: %.*s\n", int(s.size()), s.data());
      if (s[0] == '+') {
        EXPECT_TRUE(MatchSubstring(m, s.substr(1))) << "re: " << vec[0] << " s: " << s;
      } else {
        assert(s[0] == '-');
        EXPECT_FALSE(MatchSubstring(m, s.substr(1))) << "re: " << vec[0] << " s: " << s;
      }
    }
  }
}
gperftools-gperftools-2.18/benchmark/unwind_bench.cc000066400000000000000000000067171513545575200227450ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
#include "config.h"

#include "base/basictypes.h"
#include "gperftools/stacktrace.h"

#include 
#include 
#include 
#if HAVE_LIBUNWIND_H
#include 
#endif

#include "run_benchmark.h"

#if defined(__GNUC__) && defined(__has_attribute)
#if defined(__linux__) && defined(__x86_64__) && defined(_LP64) && __has_attribute(naked)

#include 
#include 

#define BENCHMARK_UCONTEXT_STUFF 1

extern "C" void getcontext_light(ucontext_t *ctx);

#define R(r) offsetof(ucontext_t, uc_mcontext.gregs[r])

__attribute__((naked))
void getcontext_light(ucontext_t *ctx) {
  __asm__ __volatile__(
	"\tmovq     %%rbx, %c0(%%rdi)\n"
	"\tmovq     %%rbp, %c1(%%rdi)\n"
	"\tmovq     %%r12, %c2(%%rdi)\n"
	"\tmovq     %%r13, %c3(%%rdi)\n"
	"\tmovq     %%r14, %c4(%%rdi)\n"
	"\tmovq     %%r15, %c5(%%rdi)\n"

	"\tmovq     (%%rsp), %%rcx\n"
	"\tmovq     %%rcx, %c6(%%rdi)\n"
	"\tleaq     8(%%rsp), %%rcx\n"                /* Exclude the return address.  */
	"\tmovq     %%rcx, %c7(%%rdi)\n"
	"\tret\n"
        : : "i" (R(REG_RBX)),
          "i" (R(REG_RBP)),
          "i" (R(REG_R12)),
          "i" (R(REG_R13)),
          "i" (R(REG_R14)),
          "i" (R(REG_R15)),
          "i" (R(REG_RIP)),
          "i" (R(REG_RSP)));
}

#undef R

#endif
#endif

#define MAX_FRAMES 2048
static void *frames[MAX_FRAMES];

enum measure_mode {
  MODE_NOOP,
  MODE_WITH_CONTEXT,
  MODE_WITHOUT_CONTEXT
};

static int ATTRIBUTE_NOINLINE measure_unwind(int maxlevel, int mode) {
  int n;

  if (mode == MODE_NOOP)
    return 0;

  if (mode == MODE_WITH_CONTEXT) {
#if BENCHMARK_UCONTEXT_STUFF
    ucontext_t uc;
    getcontext_light(&uc);
    n = GetStackTraceWithContext(frames, MAX_FRAMES, 0, &uc);
#else
    abort();
#endif
  } else {
    n = GetStackTrace(frames, MAX_FRAMES, 0);
  }
  if (n < maxlevel) {
    fprintf(stderr, "Expected at least %d frames, got %d\n", maxlevel, n);
    abort();
  }
  return 0;
}

static int ATTRIBUTE_NOINLINE frame_forcer(int rv) {
#ifdef __GNUC__
  // aargh, clang is too smart and it optimizes out f1 "loop" even
  // despite frame_forcer trick. So lets resort to less portable asm
  // volatile thingy.
  __asm__ __volatile__ ("");
#endif
  return rv;
}

static int ATTRIBUTE_NOINLINE f1(int level, int maxlevel, int mode) {
  if (level == maxlevel)
    return frame_forcer(measure_unwind(maxlevel, mode));
  return frame_forcer(f1(level + 1, maxlevel, mode));
}

static void bench_unwind_no_op(long iterations, uintptr_t param) {
  do {
    f1(0, param, MODE_NOOP);
    iterations -= param;
  } while (iterations > 0);
}

#if BENCHMARK_UCONTEXT_STUFF
static void bench_unwind_context(long iterations, uintptr_t param) {
  do {
    f1(0, param, MODE_WITH_CONTEXT);
    iterations -= param;
  } while (iterations > 0);
}
#endif

static void bench_unwind_no_context(long iterations, uintptr_t param) {
  do {
    f1(0, param, MODE_WITHOUT_CONTEXT);
    iterations -= param;
  } while (iterations > 0);
}

int main(int argc, char **argv) {
  init_benchmark(&argc, &argv);

#if BENCHMARK_UCONTEXT_STUFF
  report_benchmark("unwind_context", bench_unwind_context, 1024);
#endif
  report_benchmark("unwind_no_context", bench_unwind_no_context, 1024);
  report_benchmark("unwind_no_op", bench_unwind_no_op, 1024);

//// TODO: somehow this fails at linking step. Figure out why this is missing
// #if HAVE_LIBUNWIND_H
//   unw_set_caching_policy(unw_local_addr_space, UNW_CACHE_PER_THREAD);
// #endif
  return 0;
}
gperftools-gperftools-2.18/cmake/000077500000000000000000000000001513545575200171065ustar00rootroot00000000000000gperftools-gperftools-2.18/cmake/DefineTargetVariables.cmake000066400000000000000000000020261513545575200243020ustar00rootroot00000000000000if(NOT COMMAND check_cxx_source_compiles)
  include(CheckCXXSourceCompiles)
endif()

macro(define_target_variables)
  check_cxx_source_compiles("int main() { return __i386__; }" i386)
  check_cxx_source_compiles("int main() { return __x86_64__; }" x86_64)
  check_cxx_source_compiles("int main() { return __s390__; }" s390)
if(APPLE)
  check_cxx_source_compiles("int main() { return __arm64__; }" ARM)
  check_cxx_source_compiles("int main() { return __ppc64__; }" PPC64)
  check_cxx_source_compiles("int main() { return __ppc__; }" PPC)
else()
  check_cxx_source_compiles("int main() { return __arm__; }" ARM)
  check_cxx_source_compiles("int main() { return __PPC64__; }" PPC64)
  check_cxx_source_compiles("int main() { return __PPC__; }" PPC)
endif()
  check_cxx_source_compiles("int main() { return __FreeBSD__; }" FreeBSD)
  check_cxx_source_compiles("int main() { return __MINGW__; }" MINGW)
  check_cxx_source_compiles("int main() { return __linux; }" LINUX)
  check_cxx_source_compiles("int main() { return __APPLE__; }" OSX)
endmacro()
gperftools-gperftools-2.18/cmake/config.h.in000066400000000000000000000121201513545575200211250ustar00rootroot00000000000000#ifndef GPERFTOOLS_CONFIG_H_
#define GPERFTOOLS_CONFIG_H_

/* Enable aggressive decommit by default */
#cmakedefine ENABLE_AGGRESSIVE_DECOMMIT_BY_DEFAULT

/* Build runtime detection for sized delete */
#cmakedefine ENABLE_DYNAMIC_SIZED_DELETE

/* Report large allocation */
#cmakedefine ENABLE_LARGE_ALLOC_REPORT

/* Build sized deletion operators */
#cmakedefine ENABLE_SIZED_DELETE

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_ASM_PTRACE_H

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_CYGWIN_SIGNAL_H

/* Define to 1 if you have the declaration of `backtrace', and to 0 if you
   don't. */
#cmakedefine01 HAVE_DECL_BACKTRACE

/* Define to 1 if you have the declaration of `memalign', and to 0 if you
   don't. */
#cmakedefine01 HAVE_DECL_MEMALIGN

/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
   don't. */
#cmakedefine01 HAVE_DECL_NANOSLEEP

/* Define to 1 if you have the declaration of `posix_memalign', and to 0 if
   you don't. */
#cmakedefine01 HAVE_DECL_POSIX_MEMALIGN

/* Define to 1 if you have the declaration of `pvalloc', and to 0 if you
   don't. */
#cmakedefine01 HAVE_DECL_PVALLOC

/* Define to 1 if you have the declaration of `sleep', and to 0 if you don't.
   */
#cmakedefine01 HAVE_DECL_SLEEP

/* Define to 1 if you have the declaration of `valloc', and to 0 if you don't.
   */
#cmakedefine01 HAVE_DECL_VALLOC

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_EXECINFO_H

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_FCNTL_H

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_FEATURES_H

/* Define to 1 if you have the `geteuid' function. */
#cmakedefine HAVE_GETEUID

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_GLOB_H

/* Define to 1 if you have the  header file. */
#cmakedefine01 HAVE_LIBUNWIND_H

#cmakedefine USE_LIBUNWIND

/* Define if this is Linux that has SIGEV_THREAD_ID */
#cmakedefine01 HAVE_LINUX_SIGEV_THREAD_ID

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_MALLOC_H

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_MALLOC_MALLOC_H

/* Define to 1 if you have a working `mmap' system call. */
#cmakedefine HAVE_MMAP

/* define if libc has program_invocation_name */
#cmakedefine HAVE_PROGRAM_INVOCATION_NAME

/* Define to 1 if you have the `sbrk' function. */
#cmakedefine HAVE_SBRK

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_SCHED_H

/* Define to 1 if the system has the type `struct mallinfo'. */
#cmakedefine HAVE_STRUCT_MALLINFO

/* Define to 1 if the system has the type `struct mallinfo2'. */
#cmakedefine HAVE_STRUCT_MALLINFO2

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_SYS_CDEFS_H

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_SYS_MALLOC_H

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_SYS_SOCKET_H

/* Define to 1 if you have the  header file. */
#cmakedefine01 HAVE_SYS_SYSCALL_H

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_SYS_TYPES_H

/* Define to 1 if you have the  header file. */
#cmakedefine01 HAVE_SYS_UCONTEXT_H

/* Define to 1 if you have the  header file. */
#cmakedefine01 HAVE_UCONTEXT_H

/* Define to 1 if you have the  header file. */
#cmakedefine HAVE_UNISTD_H

/* Whether  contains _Unwind_Backtrace */
#cmakedefine HAVE_UNWIND_BACKTRACE

// __cxxabiv1::__cxa_demangle is available
#cmakedefine01 HAVE_CXA_DEMANGLE

/* define if your compiler has __attribute__ */
#cmakedefine HAVE___ATTRIBUTE__

/* define if your compiler supports alignment of functions */
#cmakedefine HAVE___ATTRIBUTE__ALIGNED_FN

/* 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
   used internally, to compile the DLL, and every DLL source file #includes
   "config.h" before anything else. */
#if defined(_WIN32)
#ifndef PERFTOOLS_DLL_DECL
# define PERFTOOLS_IS_A_DLL  1
# define PERFTOOLS_DLL_DECL  __declspec(dllexport)
# define PERFTOOLS_DLL_DECL_FOR_UNITTESTS  __declspec(dllimport)
#endif
#else
#ifndef PERFTOOLS_DLL_DECL
# define PERFTOOLS_DLL_DECL
# define PERFTOOLS_DLL_DECL_FOR_UNITTESTS
#endif
#endif

/* if libgcc stacktrace method should be default */
#cmakedefine PREFER_LIBGCC_UNWINDER

/* Define 8 bytes of allocation alignment for tcmalloc */
#cmakedefine TCMALLOC_ALIGN_8BYTES

/* Define internal page size for tcmalloc as number of left bitshift */
#cmakedefine TCMALLOC_PAGE_SIZE_SHIFT @TCMALLOC_PAGE_SIZE_SHIFT@

/* C99 says: define this to get the PRI... macros from stdint.h */
#ifndef __STDC_FORMAT_MACROS
# define __STDC_FORMAT_MACROS 1
#endif

#ifdef _WIN32
// TODO(csilvers): include windows/port.h in every relevant source file instead?
#include "windows/port.h"
#endif  /* _WIN32 */

#endif  /* GPERFTOOLS_CONFIG_H_ */
gperftools-gperftools-2.18/cmake/pkgconfig.pc000066400000000000000000000005571513545575200214100ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@

Name: @CMAKE_PROJECT_NAME@
Version: @CMAKE_PROJECT_VERSION@
Description: @CMAKE_PROJECT_DESCRIPTION@
URL: @CMAKE_PROJECT_HOMEPAGE_URL@
Requires:
Libs: -L${libdir} -l@NAME@
Libs.private:@PTHREAD_FLAGS@
Cflags: -I${includedir}

gperftools-gperftools-2.18/configure.ac000066400000000000000000000514251513545575200203230ustar00rootroot00000000000000## Process this file with autoconf to produce configure.
## In general, the safest way to proceed is to run ./autogen.sh

# make sure we're interpreted by some minimal autoconf
AC_PREREQ([2.69])

AC_INIT([gperftools],[2.18],[gperftools@googlegroups.com])
# Update this value for every release!  (A:B:C will map to foo.so.(A-C).C.B)
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
TCMALLOC_SO_VERSION=10:4:6
PROFILER_SO_VERSION=5:18:5
TCMALLOC_AND_PROFILER_SO_VERSION=11:4:7

AC_SUBST(TCMALLOC_SO_VERSION)
AC_SUBST(PROFILER_SO_VERSION)
AC_SUBST(TCMALLOC_AND_PROFILER_SO_VERSION)

# The argument here is just something that should be in the current directory
# (for sanity checking)
AC_CONFIG_SRCDIR(README)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([dist-zip foreign tar-ustar nostdinc])
AC_CONFIG_HEADERS([src/config.h])

AM_MAINTAINER_MODE()

# The user can choose not to compile in the heap-profiler, , or the
# cpu-profiler.  There's also the possibility for a 'fully minimal'
# compile, which leaves out the stacktrace code as well.  By default,
# we include all of these that the target system supports.
default_enable_cpu_profiler=yes
default_enable_heap_profiler=yes
default_enable_debugalloc=yes
default_enable_minimal=no
default_tcmalloc_alignment=16
need_nanosleep=yes   # Used later, to decide if to run ACX_NANOSLEEP
case "$host" in
   *-mingw*) default_enable_minimal=yes; default_enable_debugalloc=no;
             need_nanosleep=no;;
   *-cygwin*) default_enable_cpu_profiler=no;;
esac

# Currently only backtrace works on s390 and OSX.
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [
#if !defined(__s390__) && !defined(__APPLE__)
#error not s390 and not osx
#endif
return 1
])],
                  [default_enable_libunwind=no
                   default_enable_backtrace=yes],
                  [default_enable_libunwind=yes
                   default_enable_backtrace=no])

# Disable libunwind linking on ppc64 by default.
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [return __PPC64__])],
                  [default_enable_libunwind=no
                   default_tcmalloc_pagesize=64],
                  [default_enable_libunwind=yes
                   default_tcmalloc_pagesize=8])

AC_ARG_ENABLE([cpu-profiler],
              [AS_HELP_STRING([--disable-cpu-profiler],
                              [do not build the cpu profiler])],
              [],
              [enable_cpu_profiler="$default_enable_cpu_profiler"])
AC_ARG_ENABLE([heap-profiler],
              [AS_HELP_STRING([--disable-heap-profiler],
                              [do not build the heap profiler])],
              [],
              [enable_heap_profiler="$default_enable_heap_profiler"])
AC_ARG_ENABLE([debugalloc],
              [AS_HELP_STRING([--disable-debugalloc],
                              [do not build versions of libs with debugalloc])],
              [],
              [enable_debugalloc="$default_enable_debugalloc"])
AC_ARG_ENABLE([minimal],
              [AS_HELP_STRING([--enable-minimal],
                              [build only tcmalloc-minimal (and maybe tcmalloc-minimal-debug)])],
              [],
              [enable_minimal="$default_enable_minimal"])
if test "$enable_minimal" = yes; then
  enable_cpu_profiler=no
  enable_heap_profiler=no
fi
AC_ARG_ENABLE([stacktrace-via-backtrace],
              [AS_HELP_STRING([--enable-stacktrace-via-backtrace],
                              [enable use of backtrace() for stacktrace capturing (may deadlock)])],
              [enable_backtrace=yes],
              [enable_backtrace="$default_enable_backtrace"])
AC_ARG_ENABLE([libgcc-unwinder-by-default],
              [AS_HELP_STRING([--enable-libgcc-unwinder-by-default],
                              [prefer libgcc's _Unwind_Backtrace as default stacktrace capturing method])],
              [enable_libgcc_by_default=yes],
              [enable_libgcc_by_default=no])
AS_IF([test "x$enable_libgcc_by_default" = xyes],
      [AC_DEFINE(PREFER_LIBGCC_UNWINDER, 1, [if libgcc stacktrace method should be default])])
AC_ARG_ENABLE([libunwind],
              [AS_HELP_STRING([--enable-libunwind],
                              [enable libunwind linking])],
              [],
              [enable_libunwind="$default_enable_libunwind"])
AC_ARG_WITH([tcmalloc-pagesize],
            [AS_HELP_STRING([--with-tcmalloc-pagesize],
                            [Set the tcmalloc internal page size to 4K, 8K, 16K, 32K, 64K, 128K or 256K])],
            [],
            [with_tcmalloc_pagesize=$default_tcmalloc_pagesize])
AC_ARG_WITH([tcmalloc-alignment],
            [AS_HELP_STRING([--with-tcmalloc-alignment],
                            [Set the tcmalloc allocation alignment to 8 or 16 bytes])],
            [],
            [with_tcmalloc_alignment=$default_tcmalloc_alignment])

case "$with_tcmalloc_pagesize" in
  4)
       AC_DEFINE(TCMALLOC_PAGE_SIZE_SHIFT, 12);;
  8)
       #Default tcmalloc page size.
       ;;
  16)
       AC_DEFINE(TCMALLOC_PAGE_SIZE_SHIFT, 14);;
  32)
       AC_DEFINE(TCMALLOC_PAGE_SIZE_SHIFT, 15);;
  64)
       AC_DEFINE(TCMALLOC_PAGE_SIZE_SHIFT, 16);;
  128)
       AC_DEFINE(TCMALLOC_PAGE_SIZE_SHIFT, 17);;
  256)
       AC_DEFINE(TCMALLOC_PAGE_SIZE_SHIFT, 18,
                 [Define internal page size for tcmalloc as number of left bitshift]);;
  *)
       AC_MSG_WARN([${with_tcmalloc_pagesize}K size not supported, using default tcmalloc page size.])
esac
case "$with_tcmalloc_alignment" in
  8)
       AC_DEFINE(TCMALLOC_ALIGN_8BYTES, 1,
                 [Define 8 bytes of allocation alignment for tcmalloc]);;
  16)
       #Default tcmalloc allocation alignment.
       ;;
  *)
       AC_MSG_WARN([${with_tcmalloc_alignment} bytes not supported, using default tcmalloc allocation alignment.])
esac

# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AC_LANG([C++])
AM_CONDITIONAL(GCC, test "$GCC" = yes)   # let the Makefile know if we're gcc

AX_CXX_COMPILE_STDCXX(17, ext, mandatory)

LT_INIT

# Lets try enable frame pointers to enable simpler stacktrace
# capturing methods, but keep performace for critical bits with
# -momit-leaf-frame-pointer. However, we should be conservative so
# that we don't disable leaf frame pointers on whatever architectures
# that have them enabled by default.
AC_CACHE_CHECK(
  [compiler and target supports -fno-omit-frame-pointer -momit-leaf-frame-pointer],
  [ac_cv_frame_pointer_cflags],
  [OLD_CXXFLAGS="$CXXFLAGS"
   CXXFLAGS="$CXXFLAGS -fno-omit-frame-pointer -momit-leaf-frame-pointer"
   AC_COMPILE_IFELSE(
     [AC_LANG_PROGRAM(
#if !(__i386__ || __x86_64__ || __riscv || __aarch64__)
#error unsupported arch
#endif
     )],
     [ac_cv_frame_pointer_cflags=yes],
     [ac_cv_frame_pointer_cflags=no])
   CXXFLAGS="$OLD_CXXFLAGS"])
AM_CONDITIONAL(ENABLE_FP_FLAGS, [test "x$ac_cv_frame_pointer_cflags" = "xyes"])

# Clang-only (so far?) -Wthread-safety is a useful thing. We want.
AC_CACHE_CHECK(
  [compiler and target supports -Wthread-safety],
  [ac_cv_w_thread_safety],
  [OLD_CXXFLAGS="$CXXFLAGS"
   CXXFLAGS="$CXXFLAGS -Wthread-safety"
   AC_COMPILE_IFELSE(
     [AC_LANG_PROGRAM([], [])],
     [ac_cv_w_thread_safety=yes],
     [ac_cv_w_thread_safety=no])
   CXXFLAGS="$OLD_CXXFLAGS"])
AM_CONDITIONAL(ENABLE_W_THREAD_SAFETY, [test "x$ac_cv_w_thread_safety" = "xyes"])

AX_C___ATTRIBUTE__

AC_MSG_CHECKING(for __attribute__((aligned(N))) on functions)
AC_CACHE_VAL(ac_cv___attribute__aligned_fn, [
  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include 
     void foo(void) __attribute__((aligned(128)));
     void foo(void) { exit(1); }]], [[]])],[ac_cv___attribute__aligned_fn=yes],[ac_cv___attribute__aligned_fn=no
  ])])
if test "$ac_cv___attribute__aligned_fn" = "yes"; then
  AC_DEFINE(HAVE___ATTRIBUTE__ALIGNED_FN, 1, [define if your compiler supports alignment of functions])
fi
AC_MSG_RESULT($ac_cv___attribute__aligned_fn)


# TODO(csilvers): we could remove a lot when WITH_CPU_PROFILER etc is "no".
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
AC_CHECK_HEADERS(glob.h)        # for heap-profile-table (cleaning up profiles)
AC_CHECK_HEADERS(execinfo.h)    # for stacktrace
AC_CHECK_HEADERS(sched.h)       # for being nice in our spinlock code
AC_CHECK_HEADERS(sys/syscall.h)
AC_CHECK_HEADERS(fcntl.h)       # for tcmalloc_unittest
AC_CHECK_HEADERS(sys/cdefs.h)   # Where glibc defines __THROW

AC_CHECK_HEADERS(sys/ucontext.h)
AC_CHECK_HEADERS(ucontext.h)
AC_CHECK_HEADERS(cygwin/signal.h)        # ucontext on cywgin
AC_CHECK_HEADERS(asm/ptrace.h)           # get ptrace macros, e.g. PT_NIP

REGEX_LIBS=
# "sufficiently unix" systems need regexec for unit tests
if test "x$need_nanosleep" = xyes; then
  save_LIBS="$LIBS"
  LIBS="$REGEX_LIBS"
  # QNX needs -lregex; but lets test just in case
  AC_SEARCH_LIBS([regexec], [regex], [], [AC_MSG_ERROR([failed to locate regexec() (used for tests)])])
  REGEX_LIBS="$LIBS"
  LIBS="$save_LIBS"
fi
AC_SUBST(REGEX_LIBS)

# We override a lot of memory allocation routines, not all of which are
# standard.  For those the system doesn't declare, we'll declare ourselves.
AC_CHECK_DECLS([posix_memalign,
                memalign,
                valloc,
                pvalloc],,,
               [#define _XOPEN_SOURCE 600
                #define _QNX_SOURCE 1
                #include 
                #include ])

# We hardcode HAVE_MMAP to 1. There are no interesting systems anymore
# without functional mmap. And our windows (except mingw) builds
# aren't using autoconf. So we keep HAVE_MMAP define, but only to
# distingush windows and rest.
case "$host" in
   *-mingw*) default_emergency_malloc=no;;
   *) default_emergency_malloc=yes
      AC_DEFINE(HAVE_MMAP, 1, [Define to 1 if you have a working `mmap' system call.])
esac

# We want to access the "PC" (Program Counter) register from a struct
# ucontext.  Every system has its own way of doing that. But in case
# we're dealing with unknown system, we have to check if GetPC
# actually works. But don't bother if we're not doing cpu-profiling.
if test "$enable_cpu_profiler" = yes; then
  OLD_CXXFLAGS="$CXXFLAGS"
  CXXFLAGS="$CXXFLAGS -I$srcdir/src"
  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "getpc.h"]], [GetPC({})])],
                    [],
                    [AC_MSG_WARN(Could not find the PC.  Will not try to compile libprofiler...)
                     enable_cpu_profiler=no])
  CXXFLAGS="$OLD_CXXFLAGS"
fi

# Some tests test the behavior of .so files, and only make sense for dynamic.
AM_CONDITIONAL(ENABLE_STATIC, test "$enable_static" = yes)

# We want to link in libunwind if it is enabled and exists.
UNWIND_LIBS=
UNWIND_PC_DEP=
if test "$enable_libunwind" = yes; then
  AC_CHECK_HEADERS([libunwind.h],
                   [AC_CHECK_LIB(unwind, backtrace,
                     [UNWIND_LIBS=-lunwind
                      UNWIND_PC_DEP=libunwind
                      AC_DEFINE([USE_LIBUNWIND], [1], [libunwind.h was found and is working])
                      will_use_libunwind=yes])])
fi
AC_SUBST(UNWIND_LIBS)
AC_SUBST(UNWIND_PC_DEP)

AC_ARG_ENABLE(frame_pointers,
              AS_HELP_STRING([--enable-frame-pointers],
                             [Add -fno-omit-frame-pointer to compile flags]),
	      , enable_frame_pointers=no)
AM_CONDITIONAL(ENABLE_FRAME_POINTERS, test "$enable_frame_pointers" = yes)

AC_ARG_ENABLE([dynamic-sized-delete-support],
              [AS_HELP_STRING([--enable-dynamic-sized-delete-support],
                [try to build run-time switch for sized delete operator])],
              [enable_dyn_sized_delete="$enableval"],
              [enable_dyn_sized_delete=no])

AS_IF([test "x$enable_dyn_sized_delete" = xyes],
      [AC_DEFINE([ENABLE_DYNAMIC_SIZED_DELETE], 1,
                 [Build runtime detection for sized delete])])

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])],
      [AS_IF([test "x$enable_dyn_sized_delete" = xyes],
             [AC_MSG_NOTICE([Will build dynamically detected sized deallocation operators])],
             [AC_MSG_NOTICE([Will build sized deallocation operators that ignore size])])])

AC_CACHE_CHECK([if C++ compiler supports -fsized-deallocation],
               [perftools_cv_sized_deallocation_result],
               [OLD_CXXFLAGS="$CXXFLAGS"
                CXXFLAGS="$CXXFLAGS -fsized-deallocation"
                AC_LINK_IFELSE([AC_LANG_PROGRAM(
                    [[#include 
#include ]],
                    [[static void (* volatile ptr)(void *, size_t) = ::operator delete; (*ptr)(0, 256);]])],
                 perftools_cv_sized_deallocation_result=yes,
                 perftools_cv_sized_deallocation_result=no)
                CXXFLAGS="$OLD_CXXFLAGS"])

AM_CONDITIONAL(HAVE_SIZED_DEALLOCATION,
               test "$perftools_cv_sized_deallocation_result" = yes)

AC_CACHE_CHECK([if target has _Unwind_Backtrace],
               [perftools_cv_have_unwind_backtrace],
               [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
                    [[#include 
#if defined(__APPLE__) || defined(__FreeBSD__)
#error OSX and FreeBSD _Unwind_Backtrace recurses back to malloc
#endif
]],
                    [[&_Unwind_Backtrace]])],
                 [perftools_cv_have_unwind_backtrace=yes],
                 [perftools_cv_have_unwind_backtrace=no])])
AS_IF([test "x$perftools_cv_have_unwind_backtrace" = xyes],
      [AC_DEFINE(HAVE_UNWIND_BACKTRACE, 1, [Whether  contains _Unwind_Backtrace])])

AS_IF([test "x$will_use_libunwind" = xyes],
      [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [return __arm__])],
                         [default_emergency_malloc=yes])])

AC_ARG_ENABLE([emergency-malloc],
              [AS_HELP_STRING([--enable-emergency-malloc],
                              [build emergency malloc feature])],
              [enable_emergency_malloc="$enableval"],
              [enable_emergency_malloc="$default_emergency_malloc"])

AM_CONDITIONAL(BUILD_EMERGENCY_MALLOC, [test "x$enable_emergency_malloc" = xyes])

# Also make sure we get standard PRI... definitions, even with glibc.
# We have to use AH_VERBATIM because we need the #ifdef guard (gcc buglet)
AH_VERBATIM([__STDC_FORMAT_MACROS],
            [/* C99 says: define this to get the PRI... macros from stdint.h */
#ifndef __STDC_FORMAT_MACROS
# define __STDC_FORMAT_MACROS 1
#endif])

AC_CACHE_CHECK([if target has functional __cxa_demangle],
               [perftools_cv_have_cxa_demangle],
               [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
                    [[#include ]],
                    [[&__cxxabiv1::__cxa_demangle]])],
                  [perftools_cv_have_cxa_demangle=yes],
                  [perftools_cv_have_cxa_demangle=no])])
AS_IF([test "x$perftools_cv_have_cxa_demangle" = xyes],
      [AC_DEFINE(HAVE_CXA_DEMANGLE, 1, [Whether  contains __cxxabiv1::__cxa_demangle])])

# Nanosleep requires extra libraries on some architectures (solaris).
# This sets NANOSLEEP_LIBS.  nanosleep doesn't exist on mingw, which
# is fine for us because we don't compile libspinlock, which uses it.
if test "$need_nanosleep" = yes; then
  ACX_NANOSLEEP
  AC_SUBST(NANOSLEEP_LIBS)
fi

# In fact, a lot of the code in this directory depends on pthreads
AX_PTHREAD

# Figure out where libc has program_invocation_name
AC_PROGRAM_INVOCATION_NAME

dnl only very recent mingw has sleep and nanosleep
case "$host" in
   *-mingw*)
     AC_CHECK_DECLS([sleep], [], [], [#include ])
     AC_CHECK_DECLS([nanosleep], [], [], [#include ])
   ;;
esac

if test "x$enable_backtrace" = xyes; then
  AC_CHECK_DECLS([backtrace], [], [], [#include ])
  save_LIBS=$LIBS
  LIBS=$UNWIND_LIBS
  AC_SEARCH_LIBS([backtrace], [execinfo])
  UNWIND_LIBS=$LIBS
  LIBS=$save_LIBS
fi

STACKTRACE_UNITTEST_LIBS=
AS_IF([test "x$ac_cv_header_execinfo_h" = xyes],
  AS_IF([test "x$enable_cpu_profiler" = xyes -o "x$enable_heap_profiler" = xyes],
    [AC_CHECK_DECLS([backtrace_symbols], [], [], [#include 
                                                  ])
     save_LIBS=$LIBS
     LIBS=
     AC_SEARCH_LIBS([backtrace_symbols], [execinfo])
     STACKTRACE_UNITTEST_LIBS=$LIBS
     LIBS=$save_LIBS]))
AC_SUBST(STACKTRACE_UNITTEST_LIBS)

AC_ARG_ENABLE([hidden-visibility],
              [AS_HELP_STRING([--enable-hidden-visibility],
                              [build libraries with -fvisibility=hidden])],
              [enable_visibility=yes],
              [enable_visibility=no])

AC_DEFINE([PERFTOOLS_DLL_DECL], [], [dllexport or attribute visibility])

AS_IF([test "x$enable_visibility" = xyes],
  [AC_DEFINE([PERFTOOLS_DLL_DECL], [__attribute((visibility("default")))], [])
   CXXFLAGS="-fvisibility=hidden $CXXFLAGS"])

# In theory, config.h files shouldn't need a header guard.
# Now there were historical reasons for doing so
#   https://github.com/gperftools/gperftools/issues/248
# but these days we are keeping it mostly for consistency and safety.
AH_TOP([
#ifndef GPERFTOOLS_CONFIG_H_
#define GPERFTOOLS_CONFIG_H_
])

# MinGW uses autoconf, but also needs the windows shim routines
# (since it doesn't have its own support for, say, pthreads).
# This requires us to #include a special header file, and also to
# link in some windows versions of .o's instead of the unix versions.
#
# Also, manually mark systems where we have to be careful how early
# we run pthreads.  TODO(csilvers): turn this into an autoconf check.
AH_BOTTOM([
#ifdef _WIN32
// TODO(csilvers): include windows/port.h in every relevant source file instead?
#include "windows/port.h"
#endif

#endif  /* #ifndef GPERFTOOLS_CONFIG_H_ */
])
AM_CONDITIONAL(MINGW, expr $host : '.*-mingw' >/dev/null 2>&1)
AM_CONDITIONAL(OSX, expr $host : '.*-apple-darwin.*' >/dev/null 2>&1)

# Export the --enable flags we set above.  We do this at the end so
# other configure rules can enable or disable targets based on what
# they find.
AM_CONDITIONAL(WITH_CPU_PROFILER, test "$enable_cpu_profiler" = yes)
AM_CONDITIONAL(WITH_HEAP_PROFILER, test "$enable_heap_profiler" = yes)
AM_CONDITIONAL(WITH_DEBUGALLOC, test "$enable_debugalloc" = yes)
# We make tcmalloc.so if either heap-profiler or heap-checker is asked for.
# TODO/FIXME
AM_CONDITIONAL(WITH_HEAP_PROFILER_OR_CHECKER,
               test "$enable_heap_profiler" = yes)
# If we don't use any profilers, we don't need stack traces (or pprof)
AM_CONDITIONAL(WITH_STACK_TRACE, test "$enable_cpu_profiler" = yes -o \
                                      "$enable_heap_profiler" = yes)

have_linux_sigev_thread_id=no
AC_MSG_CHECKING([for Linux SIGEV_THREAD_ID])
AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM([[#include 
                           #include ]],
                         [[return SIGEV_THREAD_ID || CLOCK_THREAD_CPUTIME_ID || __linux;]])],
        [AC_DEFINE(HAVE_LINUX_SIGEV_THREAD_ID, 1,
                  [Define if this is Linux that has SIGEV_THREAD_ID])
         have_linux_sigev_thread_id=yes
         AC_MSG_RESULT([yes])],
        [AC_MSG_RESULT([no])])

# Disable large allocation report by default.
AC_ARG_ENABLE([large-alloc-report],
              [AS_HELP_STRING([--enable-large-alloc-report],
                              [report very large allocations to stderr])],
              [enable_large_alloc_report="$enableval"],
              [enable_large_alloc_report=no])
AS_IF([test "x$enable_large_alloc_report" = xyes],
      [AC_DEFINE([ENABLE_LARGE_ALLOC_REPORT], 1, [report large allocation])])

# Enable aggressive decommit by default
AC_ARG_ENABLE([aggressive-decommit-by-default],
              [AS_HELP_STRING([--enable-aggressive-decommit-by-default],
                              [enable aggressive decommit by default])],
              [enable_aggressive_decommit_by_default="$enableval"],
              [enable_aggressive_decommit_by_default=no])
AS_IF([test "x$enable_aggressive_decommit_by_default" = xyes],
      [AC_DEFINE([ENABLE_AGGRESSIVE_DECOMMIT_BY_DEFAULT],
                 1,
                 [enable aggressive decommit by default])])

AC_PATH_PROG(PPROF_PATH, pprof)
AM_CONDITIONAL(SKIP_PPROF_TESTS, [test "x$PPROF_PATH" = "x"])
AS_IF([test "x$PPROF_PATH" = "x"],
      [AC_MSG_WARN([pprof tool not found. Will skip several unit tests that need it. Install via go install github.com/google/pprof@latest then add \$HOME/go/bin to PATH])])

AC_PATH_PROG([ASCIIDOCTOR], [asciidoctor])
AM_CONDITIONAL([MISSING_ASCIIDOCTOR], [test "x$ASCIIDOCTOR" = "x"])
AS_IF([test "x$ASCIIDOCTOR" = "x"],
      [AC_MSG_WARN([asciidoctor tool not found. Will skip building .html documentation from .adoc])])
AC_ARG_VAR(ASCIIDOCTOR_FLAGS, [flags to pass to asciidoctor])

# Write generated configuration file
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
gperftools-gperftools-2.18/docs/000077500000000000000000000000001513545575200167565ustar00rootroot00000000000000gperftools-gperftools-2.18/docs/cpuprofile-fileformat.adoc000066400000000000000000000113401513545575200241030ustar00rootroot00000000000000= Gperftools CPU Profiler Binary Data File Format
:reproducible:

[.normal]
This file documents the binary data file format produced by the
gperftools CPU Profiler. It is one of "legacy" formats supported by
the pprof tool. For information about using the CPU Profiler, see
link:cpuprofile.html[its user guide].

The profiler source code, which generates files using this format, is at
`src/profiler.cc`.

== CPU Profile Data File Structure

CPU profile data files each consist of four parts, in order:

* Binary header
* Binary profile records
* Binary trailer
* Text list of mapped objects

The binary data is expressed in terms of "slots." These are words large
enough to hold the program's pointer type, i.e., for 32-bit programs
they are 4 bytes in size, and for 64-bit programs they are 8 bytes. They
are stored in the profile data file in the native byte order (i.e.,
little-endian for x86 and x86_64).

== Binary Header

The binary header format is show below. Values written by the profiler,
along with requirements currently enforced by the analysis tools, are
shown in parentheses.

[cols=",",options="header",]
|===
|slot |data
|0 |header count (0; must be 0)
|1 |header slots after this one (3; must be >= 3)
|2 |format version (0; must be 0)
|3 |sampling period, in microseconds
|4 |padding (0)
|===

The headers currently generated for 32-bit and 64-bit little-endian (x86
and x86_64) profiles are shown below, for comparison.

[cols=",,,,,",options="header",]
|===
| |hdr count |hdr words |version |sampling period |pad
|32-bit or 64-bit (slots) |0 |3 |0 |10000 |0

|32-bit (4-byte words in file) |`0x00000` |`0x00003` |`0x00000`
|`0x02710` |`0x00000`

|64-bit LE (4-byte words in file) |`0x00000 0x00000`
|`0x00003 0x00000` |`0x00000 0x00000` |`0x02710 0x00000`
|`0x00000 0x00000`
|===

The contents are shown in terms of slots, and in terms of 4-byte words
in the profile data file. The slot contents for 32-bit and 64-bit
headers are identical. For 32-bit profiles, the 4-byte word view matches
the slot view. For 64-bit profiles, each (8-byte) slot is shown as two
4-byte words, ordered as they would appear in the file.

The profiling tools examine the contents of the file and use the
expected locations and values of the header words field to detect
whether the file is 32-bit or 64-bit.

== Binary Profile Records

The binary profile record format is shown below.

[cols=2*]
|===
|slot
|data

|0
|sample count, must be >= 1

|1
|number of call chain PCs (num_pcs), must be >= 1

|2 .. (num_pcs + 1)
|call chain PCs, most-recently-called function first.
|===

The total length of a given record is 2 + num_pcs.

Note that multiple profile records can be emitted by the profiler having
an identical call chain. In that case, analysis tools should sum the
counts of all records having identical call chains.

*Note:* Some profile analysis tools terminate if they see _any_ profile
record with a call chain with its first entry having the address 0.
(This is similar to the binary trailer.)

=== Example

This example shows the slots contained in a sample profile record.

[cols=",,,,",]
|===
|5 |3 |0xa0000 |0xc0000 |0xe0000
|===

In this example, 5 ticks were received at PC 0xa0000, whose function had
been called by the function containing 0xc0000, which had been called
from the function containing 0xe0000.

== Binary Trailer

The binary trailer consists of three slots of data with fixed values,
shown below.

[cols=",",options="header",]
|===
|slot |value
|0 |0
|1 |1
|2 |0
|===

Note that this is the same data that would contained in a profile record
with sample count = 0, num_pcs = 1, and a one-element call chain
containing the address 0.

== Text List of Mapped Objects

The binary data in the file is followed immediately by a list of mapped
objects. This list consists of lines of text separated by newline
characters.

Each line describes one mapping as produced by SaveProcSelfMaps. For
example:

....
  40000000-40015000 r-xp 00000000 03:01 12845071   /lib/ld-2.3.2.so
....

The first address must start at the beginning of the line. This is
essentially the same format as Linux's `/proc//maps` file.
Recent Linux systems have this format documented in
link:https://man7.org/linux/man-pages/man5/proc_pid_maps.5.html[`man 5
proc_pid_maps`]. Less recent systems document it under `man 5 proc`.

Tools ignore minor:major number and inode number. And only executable
mappings really need to be present. See
`src/base/proc_maps_iterator.{h,cc}` for how it is produced.

Unrecognized lines should be ignored by analysis tools.

Note, original pprof tool also supported processing `$build`
"variable" when processing mappings, but we never produced such
mappings. So we don't document this anymore.

'''''

Original authror: Chris Demetriou (cgd) +
Last update by: Aliaksei Kandratsenka +
gperftools-gperftools-2.18/docs/cpuprofile.adoc000066400000000000000000000364021513545575200217630ustar00rootroot00000000000000= Using CPU Profiler

:reproducible:

[.normal]
This is the CPU profiler originally developed at Google. There are
three parts to using it: linking the library into an application,
running the code, and analyzing the output.

On the off-chance that you should need to understand it, the CPU
profiler data file format is documented separately,
link:cpuprofile-fileformat.html[here].

== Linking in the Library

To install the CPU profiler into your executable, add `-lprofiler` to
the link-time step for your executable. (It's also possible to
add in the profiler at run-time using `+LD_PRELOAD+`, e.g.

 % LD_PRELOAD="/usr/lib/libprofiler.so" 

This does _not_ turn on CPU profiling; it just inserts the code. For
that reason, it's practical to just always link `+-lprofiler+` into a
binary while developing; that's what we do at Google. (However, since
any user can turn on the profiler by setting an environment variable,
it's not necessarily recommended to install profiler-linked binaries
into a production, running system.)

== Running the Code

There are several alternatives to actually turn on CPU profiling for a
given run of an executable:

. Define the environment variable CPUPROFILE to the filename to dump the
profile to. For instance, if you had a version of `+/bin/ls+` that had
been linked against libprofiler, you could run:
+
....
% env CPUPROFILE=ls.prof /bin/ls
....
. In addition to defining the environment variable CPUPROFILE you can
also define CPUPROFILESIGNAL. This allows profiling to be controlled via
the signal number that you specify. The signal number must be unused by
the program under normal operation. Internally it acts as a switch,
triggered by the signal, which is off by default. For instance, if you
had a copy of `+/bin/chrome+` that had been been linked against
libprofiler, you could run:
+
....
% env CPUPROFILE=chrome.prof CPUPROFILESIGNAL=12 /bin/chrome &
....
+
You can then trigger profiling to start:
+
....
% killall -12 chrome
....
+
Then after a period of time you can tell it to stop which will generate
the profile:
+
....
% killall -12 chrome
....
. In your code, bracket the code you want profiled in calls to
`+ProfilerStart()+` and `+ProfilerStop()+`. (These functions are
declared in `++`.) `+ProfilerStart()+` will take
the profile-filename as an argument.

Profiling works correctly with sub-processes: each child process gets
its own profile with its own name (generated by combining CPUPROFILE
with the child's process id).

For security reasons, CPU profiling will not write to a file -- and is
thus not usable -- for setuid programs.

See the include-file `+gperftools/profiler.h+` for advanced-use
functions, including `+ProfilerFlush()+` and
`+ProfilerStartWithOptions()+`.

=== Modifying Runtime Behavior

You can more finely control the behavior of the CPU profiler via
environment variables.

[cols=",,",]
|===
|`CPUPROFILE_FREQUENCY=__x__` |default: 100 |How many
interrupts/second the cpu-profiler samples.

|`+CPUPROFILE_REALTIME=1+` |default: [not set] |If set to any value
(including 0 or the empty string), use ITIMER_REAL instead of
ITIMER_PROF to gather profiles. In general, ITIMER_REAL is not as
accurate as ITIMER_PROF, and also interacts badly with use of alarm(),
so prefer ITIMER_PROF unless you have a reason prefer ITIMER_REAL.
|===

== [#pprof]#Analyzing the Output#

`+pprof+` is the program used to analyze a profiles. Get it from
link:https://github.com/google/pprof[]. For example by running:

  % go install github.com/google/pprof@latest

You can then add `$HOME/go/bin` to your `$PATH`. Also, note, that they
have their own documentation as well. So check it out
link:https://github.com/google/pprof/blob/main/doc/README.md[here].

It has many output modes, both textual and graphical. Some give just
raw numbers, much like the `+-pg+` output of `+gcc+`, and others show
the data in the form of a dependency graph.

Here are some ways to call pprof. These are described in more detail
below.

....
% pprof /bin/ls ls.prof
                       Enters "interactive" mode
% pprof --text /bin/ls ls.prof
                       Outputs one line per procedure
% pprof --gv /bin/ls ls.prof
                       Displays annotated call-graph via 'gv'
% pprof --gv --focus=Mutex /bin/ls ls.prof
                       Restricts to code paths including a .*Mutex.* entry
% pprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
                       Code paths including Mutex but not string
% pprof --list=getdir /bin/ls ls.prof
                       (Per-line) annotated source listing for getdir()
% pprof --disasm=getdir /bin/ls ls.prof
                       (Per-PC) annotated disassembly for getdir()
% pprof --text localhost:1234
                       Outputs one line per procedure for localhost:1234
% pprof --callgrind /bin/ls ls.prof
                       Outputs the call information in callgrind format

% pprof --http=: /bin/ls ls.prof
                       Starts Web UI and launches web browser
                       for interactive profile inspection
....

=== Analyzing Text Output

Text mode has lines of output that look like this:

....
       14   2.1%  17.2%       58   8.7% std::_Rb_tree::find
....

Here is how to interpret the columns:

. Number of profiling samples in this function
. Percentage of profiling samples in this function
. Percentage of profiling samples in the functions printed so far
. Number of profiling samples in this function and its callees
. Percentage of profiling samples in this function and its callees
. Function name

=== Analyzing Callgrind Output

Use http://kcachegrind.sourceforge.net[kcachegrind] to analyze your
callgrind output:

....
% pprof --callgrind /bin/ls ls.prof > ls.callgrind
% kcachegrind ls.callgrind
....

The cost is specified in 'hits', i.e. how many times a function appears
in the recorded call stack information. The 'calls' from function a to b
record how many times function b was found in the stack traces directly
below function a.

Tip: if you use a debug build the output will include file and line
number information and kcachegrind will show an annotated source code
view.

=== Node Information

In the various graphical modes of pprof, the output is a call graph
annotated with timing information, like so:

link:pprof-test-big.gif[]

image:pprof-test.gif[pprof-test]

Each node represents a procedure. The directed edges indicate caller to
callee relations. Each node is formatted as follows:

....
Class Name
Method Name
local (percentage)
of cumulative (percentage)
....

The last one or two lines contains the timing information. (The
profiling is done via a sampling method, where by default we take 100
samples a second. Therefor one unit of time in the output corresponds to
about 10 milliseconds of execution time.) The "local" time is the time
spent executing the instructions directly contained in the procedure
(and in any other procedures that were inlined into the procedure). The
"cumulative" time is the sum of the "local" time and the time spent in
any callees. If the cumulative time is the same as the local time, it is
not printed.

For instance, the timing information for test_main_thread() indicates
that 155 units (about 1.55 seconds) were spent executing the code in
`+test_main_thread()+` and 200 units were spent while executing
`+test_main_thread()+` and its callees such as `+snprintf()+`.

The size of the node is proportional to the local count. The percentage
displayed in the node corresponds to the count divided by the total run
time of the program (that is, the cumulative count for `+main()+`).

=== Edge Information

An edge from one node to another indicates a caller to callee
relationship. Each edge is labelled with the time spent by the callee on
behalf of the caller. E.g, the edge from `+test_main_thread()+` to
`+snprintf()+` indicates that of the 200 samples in
`+test_main_thread()+`, 37 are because of calls to `+snprintf()+`.

Note that `+test_main_thread()+` has an edge to `+vsnprintf()+`, even
though `+test_main_thread()+` doesn't call that function directly. This
is because the code was compiled with `+-O2+`; the profile reflects the
optimized control flow.

=== Meta Information

The top of the display should contain some meta information like:

....
      /tmp/profiler2_unittest
      Total samples: 202
      Focusing on: 202
      Dropped nodes with <= 1 abs(samples)
      Dropped edges with <= 0 samples
....

This section contains the name of the program, and the total samples
collected during the profiling run. If the `+--focus+` option is on (see
the link:#focus[Focus] section below), the legend also contains the
number of samples being shown in the focused display. Furthermore, some
unimportant nodes and edges are dropped to reduce clutter. The
characteristics of the dropped nodes and edges are also displayed in the
legend.

=== [#focus]#Focus and Ignore#

You can ask pprof to generate a display focused on a particular piece of
the program. You specify a regular expression. Any portion of the
call-graph that is on a path which contains at least one node matching
the regular expression is preserved. The rest of the call-graph is
dropped on the floor. For example, you can focus on the `+vsnprintf()+`
libc call in `+profiler2_unittest+` as follows:

....
% pprof --gv --focus=vsnprintf /tmp/profiler2_unittest test.prof
....

link:pprof-vsnprintf-big.gif[]

[cols="",]
|===
|image:pprof-vsnprintf.gif[pprof-vsnprintf]
|===

Similarly, you can supply the `+--ignore+` option to ignore samples that
match a specified regular expression. E.g., if you are interested in
everything except calls to `+snprintf()+`, you can say:

....
% pprof --gv --ignore=snprintf /tmp/profiler2_unittest test.prof
....

=== Text interactive mode

By default -- if you don't specify any flags to the contrary -- pprof
runs in interactive mode. At the `+(pprof)+` prompt, you can run many of
the commands described above. You can type `+help+` for a list of what
commands are available in interactive mode.

=== [#options]#pprof Options#

For a complete list of pprof options, you can run `+pprof --help+`.

==== Output Type

[width="100%",cols="50%,50%",]
|===
|`+--text+` |Produces a textual listing. (Note: If you have an X
display, and `+dot+` and `+gv+` installed, you will probably be happier
with the `+--gv+` output.)

|`+--gv+` |Generates annotated call-graph, converts to postscript, and
displays via gv (requres `+dot+` and `+gv+` be installed).

|`+--dot+` |Generates the annotated call-graph in dot format and emits
to stdout (requres `+dot+` be installed).

|`+--ps+` |Generates the annotated call-graph in Postscript format and
emits to stdout (requres `+dot+` be installed).

|`+--pdf+` |Generates the annotated call-graph in PDF format and emits
to stdout (requires `+dot+` and `+ps2pdf+` be installed).

|`+--gif+` |Generates the annotated call-graph in GIF format and emits
to stdout (requres `+dot+` be installed).

|`--list=<__regexp__>` |
Outputs source-code listing of routines whose name matches .
Each line in the listing is annotated with flat and cumulative sample
counts.

In the presence of inlined calls, the samples associated with inlined
code tend to get assigned to a line that follows the location of the
inlined call. A more precise accounting can be obtained by disassembling
the routine using the --disasm flag.

|`--disasm=<__regexp__>` |Generates disassembly of routines that
match , annotated with flat and cumulative sample counts and
emits to stdout.
|===

==== Reporting Granularity

By default, pprof produces one entry per procedure. However you can use
one of the following options to change the granularity of the output.

[cols=2*]
|===
|`+--addresses+`
|Produce one node per program address.

|`+--lines+`
|Produce one node per source line.

|`+--functions+`
|Produce one node per function (this is the default).

|`+--files+`
|Produce one node per source file.
|===

==== Controlling the Call Graph Display

Some nodes and edges are dropped to reduce clutter in the output
display. The following options control this effect:

[cols=",",]
|===
|`+--nodecount=+` |This option controls the number of displayed
nodes. The nodes are first sorted by decreasing cumulative count, and
then only the top N nodes are kept. The default value is 80.

|`+--nodefraction=+` |This option provides another mechanism for
discarding nodes from the display. If the cumulative count for a node is
less than this option's value multiplied by the total count for the
profile, the node is dropped. The default value is 0.005; i.e. nodes
that account for less than half a percent of the total time are dropped.
A node is dropped if either this condition is satisfied, or the
--nodecount condition is satisfied.

|`+--edgefraction=+` |This option controls the number of displayed
edges. First of all, an edge is dropped if either its source or
destination node is dropped. Otherwise, the edge is dropped if the
sample count along the edge is less than this option's value multiplied
by the total count for the profile. The default value is 0.001; i.e.,
edges that account for less than 0.1% of the total time are dropped.

|`+--focus=+` |This option controls what region of the graph is
displayed based on the regular expression supplied with the option. For
any path in the callgraph, we check all nodes in the path against the
supplied regular expression. If none of the nodes match, the path is
dropped from the output.

|`+--ignore=+` |This option controls what region of the graph is
displayed based on the regular expression supplied with the option. For
any path in the callgraph, we check all nodes in the path against the
supplied regular expression. If any of the nodes match, the path is
dropped from the output.
|===

The dropped edges and nodes account for some count mismatches in the
display. For example, the cumulative count for `+snprintf()+` in the
first diagram above was 41. However the local count (1) and the count
along the outgoing edges (12+1+20+6) add up to only 40.

== Caveats

* If the program exits because of a signal, the generated profile will
be incomplete, and may perhaps be completely empty.

* The displayed graph may have disconnected regions because of the
edge-dropping heuristics described above.

* If the program linked in a library that was not compiled with enough
symbolic information, all samples associated with the library may be
charged to the last symbol found in the program before the
library. This will artificially inflate the count for that symbol.

* If you run the program on one machine, and profile it on another,
and the shared libraries are different on the two machines, the
profiling output may be confusing: samples that fall within shared
libaries may be assigned to arbitrary procedures.

* If your program forks, the children will also be profiled (since
they inherit the same CPUPROFILE setting). Each process is profiled
separately; to distinguish the child profiles from the parent profile
and from each other, all children will have their process-id appended
to the CPUPROFILE name.

* Due to a hack we use to trigger appending of pid in child processes,
your profiles may end up named strangely if the first character of
your CPUPROFILE variable has ascii value greater than 127. This should
be exceedingly rare, but if you need to use such a name, just set
prepend `+./+` to your filename: `+CPUPROFILE=./Ägypten+`.

'''''

Original author: Sanjay Ghemawat +
Last updated by: Aliaksei Kandratsenka
gperftools-gperftools-2.18/docs/dots/000077500000000000000000000000001513545575200177275ustar00rootroot00000000000000gperftools-gperftools-2.18/docs/dots/README000066400000000000000000000001271513545575200206070ustar00rootroot00000000000000This directory contains original graphviz sources of diagrams used in
gperftools docs.
gperftools-gperftools-2.18/docs/dots/overview.dot000066400000000000000000000003571513545575200223120ustar00rootroot00000000000000digraph Overview {
node [shape = box]

{rank=same
T1 [label="Thread Cache"]
Tsep [label="...", shape=plaintext]
Tn [label="Thread Cache"]
T1 -> Tsep -> Tn [style=invis]
}

C [label="Central\nHeap"]
T1 -> C [dir=both]
Tn -> C [dir=both]

}
gperftools-gperftools-2.18/docs/dots/pageheap.dot000066400000000000000000000012631513545575200222130ustar00rootroot00000000000000digraph PageHeap {
rankdir=LR
node [shape=box, width=0.3, height=0.3]
nodesep=.05

heap [shape=record, height=3, label="1 page|2 pages|3 pages|...|128 pages"]
O0 [shape=record, label=""]
O1 [shape=record, label=""]
O2 [shape=record, label="{|}"]
O3 [shape=record, label="{|}"]
O4 [shape=record, label="{||}"]
O5 [shape=record, label="{||}"]
O6 [shape=record, label="{|...|}"]
O7 [shape=record, label="{|...|}"]
sep1 [shape=plaintext, label="..."]
sep2 [shape=plaintext, label="..."]
sep3 [shape=plaintext, label="..."]
sep4 [shape=plaintext, label="..."]

heap:f0 -> O0 -> O1 -> sep1
heap:f1 -> O2 -> O3 -> sep2
heap:f2 -> O4 -> O5 -> sep3
heap:f128 -> O6 -> O7 -> sep4

}
gperftools-gperftools-2.18/docs/dots/spanmap.dot000066400000000000000000000005631513545575200221020ustar00rootroot00000000000000digraph SpanMap {
node [shape=box, width=0.3, height=0.3]
nodesep=.05

map [shape=record, width=6, label="||||||||||"]
S0 [label="a"]
S1 [label="b"]
S2 [label="c"]
S3 [label="d"]
map:f0 -> S0
map:f1 -> S0
map:f2 -> S1
map:f3 -> S2
map:f4 -> S2
map:f5 -> S2
map:f6 -> S2
map:f7 -> S2
map:f8 -> S3
map:f9 -> S3
map:f10 -> S3

}
gperftools-gperftools-2.18/docs/dots/threadheap.dot000066400000000000000000000006741513545575200225530ustar00rootroot00000000000000digraph ThreadHeap {
rankdir=LR
node [shape=box, width=0.3, height=0.3]
nodesep=.05

heap [shape=record, height=2, label="class 0|class 1|class 2|..."]
O0 [label=""]
O1 [label=""]
O2 [label=""]
O3 [label=""]
O4 [label=""]
O5 [label=""]
sep1 [shape=plaintext, label="..."]
sep2 [shape=plaintext, label="..."]
sep3 [shape=plaintext, label="..."]

heap:f0 -> O0 -> O1 -> sep1
heap:f1 -> O2 -> O3 -> sep2
heap:f2 -> O4 -> O5 -> sep3

}
gperftools-gperftools-2.18/docs/heap-example1.png000066400000000000000000001113631513545575200221200ustar00rootroot00000000000000PNG


IHDR87 IDATxy\L3̴״v*
(QZ,ى'[
JE(TʮEE*gKNM4>?󛧧y3{N|ι瞃pRmmmAA;x>PEEqi>
h>{		]pAOO_HHp̙o޼>vɞ=<8!L&jkkkmme]^^x̌靝***x}}}pAWC]H$G0S^^^Cw!##r_KII `AW4ÇqKIIUWW񕗗P(SSS@yy8hii񣸸a~~bGGB W"T[[d2CBBZ[[?|E 4EFF%%%Q(t~yyEEE&:[_SApŘ7ng0Q~x+"l6`0áL&3##366CB_SSSUU_UUf;;IO͞=kY2***:::_ 臃Whԩ'(
`0;ىbG0u9ʕ+P(+bbb,!`rIII!n!o &&F* %%%)Bē`r58=A}DCO69y!'t_~`d`2^^ާO@ `o ;A Aă`r A0C !xLA<&w ;A Aă`r A0C 8k׮h4vF7jRĉ,kbSo80l+WPPPy葈Ȝ96Ƈ"m_r寿<ϝ;;0,3!SVVVh4??	DErs󺺺8R_RR͛tVYY5aC>~Dmmm

&MZ`̵k[lioop!͆3pA/}kii7n ӧOVV&M"[2ٳ;
F8hsjj*ZKK͛A>GH$"$7F,3p_Xb# h}ྞ4i0FAHH2{Ӈ;
FG555'''&p `r^^^A#rjss}F^[sp3fpGA{gbڸq*vyyy$i}r$HII#3CЈyjmmxҍ7pl6JFFF>}fwptӧϼw
Xd~+DbKnnZZV>}pD"hJJJ$QSSs֬Ycƌ߿_VV^`v:,aaa77٠yxÆ,+338˗΋CCCtuu=<q⤘c۸qV>>Ofeeb""#C8;/---AlX5III@UUիWP!JB[u͛7?!={|>[4B}I>711>>iiicc㰰;wPhhhlY㢭Q\\ܻڵ01'N]ݽgʕ+n6i(
7nڿ+W}𱶶nժQQ7:;;_477BOx!Ū:wW>|DNN> DxxDYYĉO`<<~8qDQQ+V`؏?V^ERqqYz]v޾C}||TUUDEE={IW^q8쮮׿{J?~HMM5E f͚zҒ\333!!wP2227o`nn8}O0qW**g͚P:5kRd3FYYa75_Gpw'OpUs̉f2eX#G+**zd		!,--1vsx>>>www:Ϝ9x${ǧTo޼IPP;GEE.?m+n
% ߻Fgddlܸ;HsBYY9,ZXص.X[3-
20a޽{߾};uֽ_FWZwp"7


###e6-##B⢤faaUV
+++Phaa۷oy?h8ޞB?A@@`X#yjGqƚihh#_qŷmۊf;޽{gϞdeesMM[6n8o<4k٨3F]]
(Jssw-
Znb#""|

?Dgg9s$$$
\7lP(
bX---raa5k֤	)3g"GCYYY/+V,}Sc/=OUUgݺuaḦcu[ǚ5.WY`G/X0&Oln'n))ɋ544|||_yH}~~~YFMM?\lْ%KjjjN}֢hnҼyvׯ?{leeVjYիWHͿ>[r75QSSիW{omm;v,@IIsݺuG544tttݮYrG%&&65ؿZeeՑ#tٳg/]]cvZfM@@ӧllllىFΝŐlll.]g1$$$TT_z5cƌ߰رc--.2ܹDP***f26lCokخ}lL߳m۶.wwwP(555uoM?__߇mڴi:'O3W}}}MMŋvYYY9`@YYYm8rZp/~k+**	~ÇoݹsgR@))p8Z}VIHHpƿY,ŋ>߻~sÖ믹sVVVn޼9++mmd2~}Jjj˗[ZZv			cq5ƌe#xN))H?v -׮X,99nbFK,pg8p ///??SYYyc͘1cժUT*uo߾E Ϟ%^)++œ4PYYI&9g<T[[g`}ZKIIppDb8TUUlCt55̕+WVWW?

"jjjaǎ~"yʔ)x&l6ݻwFFF[--->{rrrT7r 993gN0~<۷;vرfuӧ[p8⴫L&s;>|XYYgYVcƌ144@PuFi޽GHH کT*
jkk]]]
hѢ;w߿omm...]]Y#  @$Y,VOOOggn޼k׮grlvQQQCC#NOKK2e
wׯw23
uM>>+Wm)))2e\6?c^,fl7oޜ
eddt=!3w_AA@HKK>>mYfq/}Nff&ޛ755O2%;;'..Bϙc5Ӎ^r΀;ummm?~D&+//?P*eeeϟ?|򆆆/x/EDDfδPs,]fFGp8[۹CR11uuu˗~ȶɓ'YY55iӦrĶN5Gѩi)))W?eddH$͛7+**g϶5kֹsGeggٙkرc޿O 4,-g$&&UTTمG455]]bg			3W\uss6ퟙq8Çih|m1cƢE>ss|RUտ]>}ĝ
&		oL`tuu,Yio?OJJwBaFmmmHHEGGZÇO>	6">!ù+
&_Qww#G?~Ś*))xq+fy.G|GB`r^߸qݻXܔ)EEEZ6xM/y8K,]nEa?/]DӱX˗^^bbX,n8gϞ1L2ֹ֒nJJJ._-..tuݰlŋMz*`0Wttt,[|l:N޽ddd~և
Awp߳~]fnnd2"""well>`˖-gwKzzzTT䰇|ܿߪU+7lufb>}zywwwppԩSh=wsqqqqq1FAA"W߂:B(J__=|p.oIIIEEŕ+Wuuu;w{捱cv1o}XXxkkr99Y--M^SSSHH;HRR_^^L&h555yjYYٳ.400\dd!+899Ǝ}K=z˗7np
%$$PJJ*77NƕS#-9u꤆̙3-,,N;644tX>b'NㄲۆH?|4
ܿDZ++kL&uU77m۶9szjh4YEEϪW^Oj`0ӦM377[+WLhрGPg e%))B>}ӧOuuu۰={6{*BwwK͟?HX,+RB""ܹǭFLMM9Nttt+Jݽ{g(""nݺE sN_Lrp+++h6M$/^Kw
NIIUQQRUU533aXLH$
ޮ
P(,d2,^Ş>}EE5>>>bb:WXXlb>|P^^>yd_dyFFFFPPfS(HݽkRTSSSmmwޭ^풞^SS{~tNNAJ__?,ښ5kͧΚ5KIIF>}zO9~~~ǎGѾ,XpᢅX*BBBI:
B 8ꪦG IDAT&%%f/^ck;رc~~V\iee@U544dǏ!m2V\\ӧk׮%$$;w#O6-X~(KLLZjձcGׯ311oyAЯ&ϱeJrN`˖-rrr}ܶWTT}Ç۷{9P^^պCq1 81111III}lll|!wvLˇ(--ݻwڵk?N߾}WUUUDϳϮ]v١.]CJ$$$:+++}+`0#*((*-1ʕ+drXXۏ9,##-`0ӦYL&?~̍0%奨eKMMMBdC&yYf٧tqzdL ՝?ߩ<|Qؿ2꺁f{y}q#JSSza<5`/^<}tΜ9_!߾}I999:::ȱzi?H,g6ɓ'@7'ExCCmllF{iiuuP2?x}7olVUUUw h,+*ꆵw:;wlxJ_u#ϟ?"f/3ȵdɒQh4gr7{qqqt:̙wn^__>RWW719`}_dFGG
fL0)Deee&rht:>yA&whUXX5cƌ>w;V\g+==;wn9rUJJٳej:+ ? //1c{[haLLL{{{ސ
%##ر䗣G>_4%''cؙ3-<ߺuuǍ7I$RJJyIIIx<~_ hC

<<U4Аh
ˆ`FD.omdH$qqq4bmѱvZgg˗sl6Jh~~ttoBG<ŋiRK,QPPjժգG޻g{#^8~~wJ(+m`=`x=>^^^3fX**phЀ
X/$$i#={ٳ䊊xznw}!oB?Մ	㽽.]H"~򡛚&&&~,^8}%' H}'266^DDBܾ}@  ))x	IJJTTTJ>{8vQEEY	BFF ,,L^^a%'
 ᰿gqww=ۖ7L&;7oi*v>hT8p`?w-[6wwUdrך5.wﮪ|*8**C`Y‚+W[L,`"yݺuwr0?~<ЈT_lYaaARRwo֖UVѨ+W/>ڹsgO{twmzN9_;G2fWZZZ޽{'%%={vuۼ3f?~<%奯,pb2Ǐ711ikkpl6o%%奾IҒc;vbLQlr%'NXt)7”W>q"Ye2#7PttӧO9ۤ?"lVdӧOsKccX`/NS(
{~;n!͡P(T*O2Br%tѢElҲQVV~I/;x |9jnns6G&JEPtgvNiii䭖ٳN_ٳӧsKFҸr%Yrr22	&##cllT677/**EvAV1NǏ_|Ⲻ#KG`rE1;v;q&[[8&	ؾSXXLXXdjhh.|EMLL,-gL0錞jHf϶.,,$}I~5g!lrJJJn5j8wJyy		'O&N@&%
 uttG6zCu!G\^vͲe#""ժQWWӁfff._b_~ݻ͋EDDBrr2y]__ק&F{l9:T

]p!Ǐ̙dܗ/SVXLlddddd4찠`
K`o_QsssHe{{{ҕҥϜ9kmm0bXoߚ3gJoL&39uideelqۿÇ;::l;'N*+hgffD"44F
$͛SN"Y**V|EZګӧO=|L&;;/jmm=w<جy_{X,Beff^x+͓3	UYYYEEU[[[B“fŷo߆`0w)))7dr7611?]`ee+Wn߾Dlkkyk`A+))qSl=%%%-Zm3f		566oݺm__ߊrW
϶ȔO`rQT:t111*JӮ>~WRR
x}YYن
쯬hoo

Ζ@fNN==$9{A;%ӧQ;wmذd2n]v͚5.ރp8?[^NNĉGiVSS0n	
ZzUeewO>9::6===++{ٲ[VݚCeS CL?h)**411sttXccc;;ۊrd22332L`;9}};wngCpÇvgM6p8Cb677]p`˖-sO.,}ʔ)-->lMB[_9sl22ThmmYliyyI[[{l6OVV]O>X`o_nvvֽ{ޢh=.DV=x͚5koߩoprrp'ǎS$"͛9sݻ̹%%%/^x7

bb?XF.\>CTWW555եKN޿7?C[nE#dddÎ;k׮Acmmݻ?0]yxl

h ^d2}|ݻw$%%@ ~H$ΛgzwYQQ|ls~k7DBrrr3;@LLLUUwfKR{w޿`(}T(?7S(!	~
MV/^<P`Xq
غuݻ~yVVV?ns|oWH`2^^ާO@ߑ#GP(96ܩ< C#̞={BB“_L6mҤ vFyyk,^\VVwメ>
B;4RXkgOm8A/6@#ѣlllLL`[<ݻw766>}BTTd#e ޡfرO>moo6ģ`rxÇLٳPlx;x&wgPSNVWWa
\ᨐ6@22k_֠v7n#B
6ˌlqqq]]]CgϞUWWn
e
111C~_ҥKm544)llljzP(FBkkRWW`0BBB}̰X..`0Z[ZZx<3"L&ykdd$((ؿ,))A2&??.3, IDAT~jᔕedd8NMM
OLL+--(**:$c0wcHe55>긩g@&&&X,vyCeeBB}nܸqBp]]]OϠٟWh		>DFFOnx굘h8w+q8oXj;_b2)K.חа[CD"""999ШQx===>@K1<<|֬ȹGDDX%&&>oY(222NNN/_&l۶Jioostt|ρz/,Lڵpq8GAF0a=S=-s5+twKJǏ7}MLL:;Ied-?5:tHLLlر11B#f011VVV


Hrp4P6//	IX,ݭagggfff_LȒ$ǷW>Jt'K \\\y6lؐ),..~=bĉ۶mEJ܆6#˵kWK묬L}߿366,#Kbmm
;~$Bq/&L4	\FlvDDđ#G&M2MHx$''`0NNNQQӧOoooG*p87ccC$%%/^:y$v„	AASL`S}6:onee7o+o嵳6ܰa}wg&vB^pA	q8*))*,,SCC3ɼ!h4zus'Jxb0BgQF}&B||ٲ#G:;/xK__'%bic
X̬!)((pbbb}]k׮=|ALLBIKKΝ3a„/Sf϶F
LfXXKp8ǏDDO<9<<|Æǎe2pww:ujJJ-[Jdee7o"''`_Ι3g-ׯ_wv^|!W?oܸq񖖖Yf|)
4m…}2;WIRSSfϞg@?~͛7kjj6m|IFF&IK{o߾kלbӦMCjr6lؐ5s.p@NV(,,XTTT#
URR~:+߾ͻr%|rwqM,]@  HREXFWv+E, "D@#E@@"5$yh=;33ÐH+.^C͚5DΖ1̄a.LIy˗W``еkWΝ~'YhѬY_644	z]KӧO)
tj45
o>sssggQm1
=
ްq84aٲeaaagΜzg%緳up]]g΅@ tugMRuuuYqql޼e4Ǐԥ

Zr֭c
wbnepqqA2CѣG/LLL444>)""pA```}yyyIIɢ"vVkzzz.\`9ֆ@ Ξ=i{``T*!66J}.d7oBCCl٢-4\i{ĉwYs/G\tZxyy;8
pjnՅ={EZbbΝ;G.LfJJDZcGWX
b0***aa׮]_}…͛˾!,,<ʕ+߽9!ľ-011<{Ey֑#"""sqqhAA{644dlss3m`0ݯ_gza0}}KH[[ݸqxFVZenn`2CCC111yyy4MWWw
YXXp6oeeeA~d*vkH//ˎS~'Ձ>¢pBBB˗?
ʚ3gNBBbDDDJJ
dupw|a]FxzDAA."""A&8]vm{AorD"auuu,a553[ZZfϞuQV=D
	HR{>,**PLL@H-[̛7AXͯ<ٳd-{X,VFF4B"N>}9}}0AAA(vLwwwL])£~?l7o.u/N啐()))p9###haYF}qillLLL$&&

Ο?sO)hOkժUqJHG]`-#  nw3>
r477BÂL̙3gx<BikϘ>] ꐩ_UU477uk-,̡'|CC.:wY***-[H$FGG!Ț)SXˁsΚŋhii𼼼v))xxxH$R{{zGh4wt9d2{슊>gƌSNt:ޞÑd}}}}}}$QLL(>>v4uSLD͟?5}h4ڮhkkP(ׯGppptttN,GRpPVVUWW+))4+WN2RYYe,]`aaQTTTWW@ -[&)Bioؽ{@300x"Rkkkkhh|2  `;T	 ,,దs|33fxxN@cmTuu}b
OJz~B0x__aW1L2LH$bߍd2NPH$BToEEH	H$4xF"L&
DѬ-(FR999988H$Ʉ~FRcǎ]4H$qpp`0K"<'d2D"`0<;"8y$@џe%|ٓVp/TС`4qȕ;?}6!+ܼys^wvvMKKb<<>Գ={%-k>44x[[[__۷ijj߿B___OOO__,Y+D٭fΜd2
׬Y
C&>LtpX#//y#X,6-Eqq.-}d+++:)!!W0rAGGy
$YҜ9sBB.TVVYGEE)d
ehhrcY姰scIOP(MMM,_
555WWW^wZڋ&իWxލYrɒ%w_@[D111^^^P;CCCaa.])sСp+++vfԶmէAno߮
#G쾎;*//oύ׍999mۺ}'O2sN>S[[{ܼ۷]}lB֭[~
'''H)cyyQUdD"QVVҿP(===My===|||h4ֶCXX9rdt
=}}uֆ?{[%%EysUUUUUU{qp '~**7nmmm=zTYYm װjΝ;EEEwpκr;::KJJp8ܰɽ%&w,4X*00`dtO
%''e˖{0+m\nj<  `Xv=:yT\\\^^ɓ's111ɉuwwP(!!!۷o!Ä7l`ddH"***,.^z۷٭ֆGRSSgd_Cֆ
/('77NR)_b&&&ii2ҥvv֮]/7ܡH&00?93g1,L>]KKuT*l]zիO:}Y|kΝ;srr]fiiY\\LrE斐prrd˗/;;;{zzQ8NYYyÆ
w]]]>HIIdcc=?QT?
6y&77cvXjb^^{||p۷|Y溺Uqqq6m˪ؤvvv<<Ó)>>O=y{a`~!>}r+W޿Ŋ3fEEEn:{HP[[ //?j#HӦC"o߾yC]ӎ~ee8J&..GR㡿sss̙ǷtP

"/^\n`GLMMH$ҳg6mc0ooZ:⼼Ɔo߆ڄ慅E!!#GFGG,\ʣёicc	IBoKCCCd2zπg/))anniii..zbð0&iddɳ^h4gaXfǏ,g;ҲQ=$%=355XGGG{{3xb5:::ޕ\ׯ?o33S>>^k		&M:UyS8888}a
Όs IDAT;@pϝ;w;ѷbbppp3@UU ##=}9s:;;~@QQAMmjooONNáP]v\R...
E]}zeeţG_Hݲe͛ @EEaaA//_4iT..iO:)""Bӣ	:::|||˖-nhhhiiYk)$ݻP11Q&))Lyy
RPP^d	DPSSssshJJ۶m6Mx<'xݻwJJJMMM<<<^~捂Bww7@>}zFF:77hqq	84(/bL&Ӳ#hmm'cD6Z0?wjo|qaa!&&&f_;&ߐHJJ;w||y^^{/^ʌ
ܿ]]]۷x\233G/[o޼3+,s݌dP+_xrV>
68MB	

===%
h&%++
	K;::p8@HH
APݻtҊ
z(71
+pxľ``M[f8AH$r͚$33S..t``Ux<̙3aaPk9/((H Ξ=ݻKgTUUGGGs{m߾=88wp8AA[ꌚV	ֹH$Ȁ񖕕*(Lqss6M
m
544s.]޻}...wwƍsss..;(2d+(ȧPVVO>}yxr&QT4=JY]]}ŊiiiGDGGgff>yd"GCCUTTlMX,???ww-'%%zz%eee=RRR掋
3e~
e ://oQQ1@b'ʭ[ѐʕ
p޹sr333ԈqOAOee..V))ϺL&1YYe˖*pׯnݺt={<[[[;FmdhPRR|2cIIɦϟ*]^^>I&!;w8C<==O$& ܺuD"
kC$=##c

M993H۷\x#4-,,ភq"Od|Aiii>uԗ]2bݺu@())BYYY666BRRCCP'deeĜ9sbcc3gشiӓ'>@ "q@,Y$++dxooo111xg?DĊ~hK~?}t\zu,uwޙ4i͛>0{b߿oVܹ	Opt_ZZZh4:""bW}>w\99>voK͛O_@;sꪮ>t OllD"utq7ֹ-Ytҥ/_͝;w߿OL|"((@҆e2oߖ&&&vwwKH766]hQddΓ'Ojii^mN+//^r:%%H$޽yVUU444v)!!100ŋiӦ8`/**BPv˖-%555ϟ?޷Ν)))F_q+w?y
??]Dbtt4++;NjjjAA׮]&ljjrzz	=z0%%С]]$tt/_feggCt:mΝ77WF\\LZZݻr6a`h(ʝ;w̠CII%K^~}diiivv-F]}@ffVEEt@ xpqqm޼9++ĉ㲲7T*$p~|?_ 1{r1)))%%%QVV6>@Ǐ@			w܁ܵkwWW1'''ɓEMsC)..?F6@RR倀|'Àa0RRR>>>k8\|ڵ;w"mdgg

w
NMM*(x:UUU:`αҥ,077_888())=y]M}RʕrO
h'ObVVo,

z=B}n't]vʞ={K
jd2y륥C99ٞ>ߋٳ-;[{`999ڵTwwcljD"6m߰Z[[UUU#"H$ySB,Л?ȴϟ޽ ?~Ӑh=Ţڵfnntss} oyy+W7ot/_~!L>q⤎KKKd޹sc
c'v|JJJ6n86t:Krh8L&N3L
d2ư'%Ʉאd]KӡY#$9e
5L&s}}n(w-%%%ׯcjhL`0UUUk/\[%<Ά̊ǡ=88D"mݺu"E{/..7ϏL&*|I&/8g͚׷k׮7"eee/\MNNp8,N;;;[:/''r񷴎a8Ĺs<==tzTTKа+Xx,bccژLq?qSX Uw[VTTh{b!x		ӧOܾ};;;{& 99HF x'_xr(++緰PWWwtt9S#//?//]]y;m#'aprrjkkA7H^z$((haa!!!jŋ

Ԃlcb@SLy a˖-,O?XQP𦽽]BB@ ioߖJzz`oߖlje
U@ ԤIdeeM|CAAjVGGرct:}dk ~~~?k!ߖaLЏ	8X,+@VV0o\qqqM6ںeciŦC
͛B333))arrrΜ9ÍmT444dreetϏD"!߿eNYmd2
5Va__>"zzz:,++wsswrrdsΛ2E!))	:=xɓ'>OvmYXXXNN61VIJzjeeUYYyռyVTTs6Jv!2ř374޽X'''<~UCQBWZ4N
ٲeܣGqHښxxhll|q{/{|V$iӦ~Ne_x/+4+!!;x+^>:|j(*44Uӭ4*'ih4zʕ
+T*]vڵk?$XYYݾ}kdHd@@thii9eobbeƨCzɓ_-+wxt>aaĎ=999P>?vIFPΝ00_`KjjSXl`৳O0
=pss6~E0հJII)Ұ߻WXXhmmp¨aXRR'$$ϟJ::GYYYcRԻw2ٰo,@
cvE$ϟ?ia$88=̙:A$yxOKKwww+ӈx]]]vv87;xraY{'NNׯ]VVVi],y^^͛7YFHH~81>333_~
شiʕ/^bnnQ7~Z[[32^Ν;ȻDEEmlC:n:'''UU={ͫ;/..zsww
]ݙCCCYY2so_`.8\{300@ ^^{FHJz
2\ww7@PPORn		zr|II	ŶgK`wqرQϖn۶
#T90sss8u _n]TM/^dfu000?033SkkQΚ5+9ud.\x\@}Qy`ooⲃ|p{{{__H#8޲eˤFʷ}C>>3r[[FhҸ8}G6nܰcʪxr%!==GP(4rZ

I~6ۓ9I3fHHXȐwXRR`,"))1jPX$*:qKOOORR#GJJJcĉ'OVVV
<|o.=sV^-###))i`077޹s~߳Giii}={?)	77{W45[ ??et钹(Fe0/_Yhy!D&((xÆ;vXa;|oӦ[l	k${zoݺuӦM66'&˻r助@x񢲲'Nxpccә3gzxtvސ|9p`ZZȎN<quhkkyU((xիWf??~\XXnddĚ_|:KP6mҐHJV/cccSSӧOVWWڽ{aXyyQGISSS(#``` !!'>$$$t:223fTdddOOڵmm-@[[~_
[r	d2dRIIqMM5Nc	ݻWNNn9::3X~$9uww9;;;wѨ^TQQq:Bf2
.

%I
99ĩSgJMMǏQ(d2tVvWGss"phhvKKKϝ;GKK"''G(FOO[Dѹx1d۴iɈYUUNegg9::)CR
Ѩak[tZfk111YlL:uƌпF~yzzŋo;T&Mv̧Oz{{߼MHHbΚ5̴dpG=qV(;1o߾5339s&kJÇ
>|sիG5)//311aRRRrt\OQG8|2'_,[Du͛

L ;В'-8{)Ǥ
Lƭ[Xlb?-Zbg		Bee222NyyٹӃU"??dpBL秩ɲ!c2JJJW
2ɓ'_r%Ѿ|#ަO_ikkD|+,,,--z/R:{#		ՅLu떜a}[2mgZWWcc;w$:C%''DB1ttCNL#qvvd
Ak׮MHx2vd/˗/~N%$<3gNFFKLZ	1555mm퉄O`)..NNN!̠z;w$Hjllڽ{7\`kkk8I$RJӧo=_HNN1c
"v햗$ISLuG5&殢 D7Ekkٳ222X5\\\AP&<~~~KKW^_pɓ'e˖deeO۷Dn"H쐓9qqq))3gFD|CŋG1PaGOO`Ghjj{nXBHHǩkccSZZ{W$'?d8\m[


sppXZZC22w򻺺Ν;;	9qQ8|p^^UVڮ|-Ʈp{0@SS%##ckdbcc>y8;;;]]ݢCuvvGX|NQo*<ː@QQq>꺺>9rX>))鯿F߿y&cͥKKːX,nחǧ7rIB mkk;w,
X~}ff?77̙3.]D&gϞزeAAA=/Fd2? ܤIϞ='$$B!n
eD uuaGYYCC%KsǧNu4>'}
accW^>\IxϏ;AZ֭h>>5k֨Ov`i|JXXhfK.UWWڮuX@~~~y_:{˗/?^rTn={zeˌҨTE!UUu֙hv!ww7MM͞rrr>~~샗()yQRR:rȔ
<
|'pfff-_=74
ZjU^^nWNJwG̙{ǝXӍnV]]3M6
xxP7uvv~ bbbX)o.-}ήZ#>>\YY[QQ)""bdx# `X=xr4i/سp8!!!MMe3g6Kc?yd&ӧ))\\\r33={H$(;
%99YTTpt\G* ȱtD"jŪ888Xɓyxx\]DDD<==G*
_|iiiiQԂ7Ꞟ<a`~3`Od{̙wڵL&_|EGGgT?QyEH$twwGD\wwwc)8DcԾ͐!RMnYYY$BSS_twHKK899899ĆGPPPYY͛7^GZZZ/^4ܼjc#oݗ.]^~+ǿ֓P(3999>sA"qqamCCCUttt #G,]Ȩ:Y@nJ#KUUd7k'&ҥK޾}~̬jɉL&pP:gϒ ι^#eL&稣dQ9<>>_LЉ	.p9rHYQn66֐$===6է]rڱc0gϒvÚuuu

+))QVV>v쨦&m"`ҤI/_NOϸr*@`0w?>
rrr

ݿ4WaObenp-[6|a`~ ]޿oaaiQ߈/Pmooi
3>h4H$~oǏ?~)̏7Tcbbh``~.\G|3a```~C7a```~C7a```~C7|S&JZIENDB`gperftools-gperftools-2.18/docs/heapprofile.adoc000066400000000000000000000245101513545575200221060ustar00rootroot00000000000000= Gperftools Heap Profiler
Original author: Sanjay Ghemawat

:reproducible:

[.normal]

This is the heap profiler originally developed at Google, to explore
how C++ programs manage memory.  This facility can be useful for

* Figuring out what is in the program heap at any given time
* Locating memory leaks
* Finding places that do a lot of allocation

The profiling system instruments all allocations and frees.  It
keeps track of various pieces of information per allocation site.  An
allocation site is defined as the active stack trace at the call to
`malloc`, `calloc`, `realloc`, or, `new`.

There are three parts to using it: linking the library into an
application, running the code, and analyzing the output.

== Linking in the Library

To install the heap profiler into your executable, add
`-ltcmalloc` to the link-time step for your executable.
Also, while we don't necessarily recommend this form of usage, it's
possible to add in the profiler at run-time using
`LD_PRELOAD`:

 % env LD_PRELOAD="/usr/lib/libtcmalloc.so" 

This does _not_ turn on heap profiling; it just inserts the
code.  For that reason, it's practical to just always link
`-ltcmalloc` into a binary while developing; that's what we
do at Google.  (However, since any user can turn on the profiler by
setting an environment variable, it's not necessarily recommended to
install profiler-linked binaries into a production, running
system.)  Note that if you wish to use the heap profiler, you must
also use the tcmalloc memory-allocation library.  There is no way
currently to use the heap profiler separate from tcmalloc.

== Running the Code

There are several alternatives to actually turn on heap profiling for
a given run of an executable:

. Define the environment variable HEAPPROFILE to the filename
to dump the profile to.  For instance, to profile
`/usr/local/bin/my_binary_compiled_with_tcmalloc`:

 % env HEAPPROFILE=/tmp/mybin.hprof /usr/local/bin/my_binary_compiled_with_tcmalloc

. In your code, bracket the code you want profiled in calls to
`HeapProfilerStart()` and `HeapProfilerStop()`.  (These functions are
declared in ``.)  `HeapProfilerStart()`
will take the profile-filename-prefix as an argument.  Then, as often
as you'd like before calling `HeapProfilerStop()`, you can use
`HeapProfilerDump()` or `GetHeapProfile()` to examine the profile.  In
case it's useful, `IsHeapProfilerRunning()` will tell you whether
you've already called `HeapProfilerStart()` or not.

For security reasons, heap profiling will not write to a file -- and
is thus not usable -- for setuid programs.

=== Modifying Runtime Behavior

You can more finely control the behavior of the heap profiler via
environment variables.

[cols=3*]
|===
|`HEAP_PROFILE_ALLOCATION_INTERVAL`
|default: 1073741824 (1 Gb)
|Dump heap profiling information each time the specified number of
bytes has been allocated by the program.

|`HEAP_PROFILE_INUSE_INTERVAL`
|default: 104857600 (100 Mb)
|Dump heap profiling information whenever the high-water memory
usage mark increases by the specified number of bytes.

|`HEAP_PROFILE_TIME_INTERVAL`
|default: 0
|Dump heap profiling information each time the specified
number of seconds has elapsed.

|`HEAPPROFILESIGNAL`
|default: disabled
|Dump heap profiling information whenever the specified signal is sent to the
process.

|`HEAP_PROFILE_MMAP`
|default: false
|Profile `mmap`, `mremap` and `sbrk`
calls in addition
to `malloc`, `calloc`, `realloc`,
and `new`.  *NOTE:* this causes the profiler to
profile calls internal to tcmalloc, since tcmalloc and friends use
mmap and sbrk internally for allocations.  One partial solution is
to filter these allocations out when running `pprof`,
with something like
`pprof --ignore='DoAllocWithArena\|SbrkSysAllocator::Alloc\|MmapSysAllocator::Alloc`.

|`HEAP_PROFILE_ONLY_MMAP`
|default: false
|Only profile `mmap`, `mremap`, and `sbrk`
calls; do not profile
`malloc`, `calloc`, `realloc`,
or `new`.

|`HEAP_PROFILE_MMAP_LOG`
|default: false
|Log `mmap`/`munmap` calls.
|===

== Analyzing the Output

If heap-profiling is turned on in a program, the program will
periodically write profiles to the filesystem.  The sequence of
profiles will be named:

           .0000.heap
           .0001.heap
           .0002.heap
           ...

where `` is the filename-prefix supplied
when running the code (e.g. via the `HEAPPROFILE`
environment variable).  Note that if the supplied prefix
does not start with a `/`, the profile files will be
written to the program's working directory.

The profile output can be viewed by passing it to the
`pprof` tool -- the same tool that's used to analyze 


Gperftools








gperftools-gperftools-2.18/docs/overview.gif000066400000000000000000000145101513545575200213140ustar00rootroot00000000000000GIF89ay___???www!,yI8ͻ`(dihlp,tmx|pH,Ȥrl:ШtJZجvzxL.zn|N~ ANZYo  '7CANZYo  '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ 'J
A9i CP@NZ-I8ͻP@NZ!(Xk CP@NZrR0IIv'(D@NZ	ZKrj/z= sH^;B@"@ '҄`9)ubds9iA0A	9i!Xki@NZYo޽rNRAs 9iA0A	9i!Xki
)	
EQ5A!@ DP`JPI9igy
9	
EQ5A!@ DP`JPIpm9C@NZ!`rC)2J)EIP@NZYo޽rRB!ZkUUP)I8tJ)PIpm9C0!G
p

N!))	A<)!@3JB@9e@NZYo޽rRB!Q`FI`XR"!@ DaP*O
))@Ќ`Ѐ@N(R
&€@)p$!1%!P*O8	Ș``L	@ 'I8ͻP@NJC f)p		1%!P*O8	Ș``L	@ '@)a0C9		JR 
@IЀ!`@ 'I8ͻP@NJC 2	r00 &)AJ)%
!B '@N(R
a0C@Ni	@)S0NL R
@9igy
Ii0C@ ARJi4! )J&B@NA@)Zg!BRBd 	`)O S!i 39'(@ '7C9)
f$H	L@r"a@a C0s	
IAuPA D@`)@)MJP@P @ 	rj/z= *aAd "ARJ	2)<@@ !HD	3PJGa@ e3c!@B0p4	#c@$B @0ć@N V{q֥^osR0C!`8$WH@N0R:Q!@B0,9C8䔁((8N0P@R(HPrNsRI`
Šp@!	1` B1)rj/  ڋ
Z"d@#8@uB(B(B1(@R@p2 sBHHS(
hNg@N(9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '9igyrj/z= V{q֛w%(@ '0I8ͻ^{(I8ͻ^ !V{q֛wP !V{q֛wP1(H	ڋ޼@NZYoCqԠ g@NZYoC
rB '78rPSB '79rj/z?9'rj/z?JPsB '78zPSB '7!9rj/z?#9!V{q֛wI8ͻ`("@NZYo

RB '78P9igy)(rj/z?#)A V{q֛w @ '78 V{q֛wA
I8ͻ`(^B@NZYoCq$A(^Prj/z?#IB9igyĠڋ޼H V{q֛w

9igyő,'(^Prj/z?#Y^P@NZYoڋ޼H V{q֛w;(^0Gܠ V{q֛w5(@ '78^
I8ͻ`(dB9igy߂rj/z?#YP@NZYoڋ޼H% V{q֛w%(@ '78	@9igy
I8ͻ`(diNP@NZYo=B@NZYoCq$KB@NZYo}rj/z?#Y V{qwڋ޼H^S(^0G4;(^(@ '78B9igy0@ '789B9igy0^0G4K(^ V{q֛wP<%(@ '7^0G4

I8;!@ '78y^PI8w@NZYoCq$Kܠڋ<^0G4
 V{q[	rj/z?#YBI8C^0G4
RB '7ڋ޼H)BAN^0	ڋ޼H	BAN	ڋ9%rj/z?#Y'9%rj/zKI8ͻ`(di#@NZYo	I8ͻ`(di'@NZYo@NZYoCq$KD%(H	ڋ! V{q֛wP<|~|!@,,?;*ڕ8*	Hp*\(#Jĉ3^Ə wq1ɓF+S*|Iffsy:@ѣHprP1'[Zׯ`Æ`d7h~`ͪ!cIB-]_z3%ؗQག
%
prW1:Ⱥ(Wr"V=o$D2Su6ԶXGmu!6m_M#tMS0ಈ7BNQ&.mȡC06,0Vpق6t	"[:$swL؁@#Ɖab+1.µ/"	w}7C7%BBvHK(
"AG%+QO	P}hI<$
28 
	!T)rFdxbF-6XY2iPD	ÀYl2(th"kC
@BL*1-	JB%7IF^Ƒeg5P1SG9K4uWT?SlTo]Tma%WkWTլ5Ij)ڴeOCձv/򪧳hv}+_3.@
lP豜hEDא"@q2 :G-H9
`	D~‚ToERl?ѠPaP2Ey
l;!WQ8OEW˜Y0Ē(MJW2ӖT0LYL8=	|PV]kY,CF&FPB(HIR4)O5
PsÁc,U?NB9̊L9*SO@̊ed)Y?pE-k V)iFI[<!8Gp&g3XWT`&EJ	3h
!9?H0@Z@hoD9]`Y
 Fp :"Y
(\ƇbՐBX	J$N%G%V%0`g`cR&``ffՓɆ.PA()W
H"	h	5eb(()ci1G4#$cc7yO:ȓ82a@9PukyY	76X'fb,f,"glV-Gq-p>*&h8{%HQQᏢIG5Pf//B0303Ni/cʉ#%hib`DYW.*PZy	"kP2&2.30lSQlނ*:șB6ٙ9
^֔0tqnUs5Α5#6oPo@gY$>ɞAɐ%*Ipޖ4ι1Б`"3q08889`rr9?r.rMJ
7)@s:(]iBcD	,@7	W秒`?N<0ww
vLN}Z:J૊x@Xhߔj'Tw!h_SFz|Pzszz BYĺ͸zHFRg夭J'С
ܧЋ;x:د!۱xծ=h=(V药R"RRRR³RR9KŲ8QLqt[Mp}ǰsX;WKY[]{_acH+gekV.*XK'k2նaRR[рRKk	%a|˱;q۹d[A$0k?DOлI;P;۸Jǻ(ۺŋP;Ѽ'y;'۽W
k{KH.XE5xJʿi\R\U+
Ḩ
lI4Ks\Id{ssL?p"Jܾ|}$x?e.,3w~T2鱿>,F@E%LGH
`GCҊ70qwqD>8]q'#W&W9ir,G<@&]p/C	P clRx?;;Iwx,
~2
u:uZ=u:+R#Lt$,k:@[N~ot֕<֠ଊ>/{kǾmά|A?Қ|ʜ
ߺ:ZkJ7*
ZB@㷋KD-[Rln9//n%Wc諨RtTJEvforo}?D@+*B.:**S#5*DQz	۬
и
UԬ˰/?y/OîoعɸP$΅ʿ̴2Kk?_	;gperftools-gperftools-2.18/docs/pprof-test-big.gif000066400000000000000000003317161513545575200223220ustar00rootroot00000000000000GIF89a,???___!,,I8ͻ`(dihlp,tmx|pH,Ȥrl:ШtJZجvzxL.zn|N~
H*\Ȱ!@ 'ZkNǀ
r V{q֛w	K(I8ͻ`(dihlp,tmx
ڋ.Ek]8gB	!0'K! V{q!^0G4O4UWu_8go<Ȁ@NZY. !PB@NZ91I8
rj/z?#Y'+ۺ/3]7BI8Ssr(R*A(F	!ڋ#\8rj/9igyő,MՕm噮P V{q(i:!@ ' `2 rrj/κp!
I^0G4O4UWu_8g"0B@NZř r
BZ[!2	R9igMG9B@NZ#^0G4O4UWu_8goJNI8τ	Vx Srj/Κ ;OI8ͻ`(dihlp,tmt V{qh5
9i!kvB8I8B)Q9iWrj/z?#Y'+ۺ/3]
80ҁ$@"$(BAcN)
@И(I0`!!49)`!9A$xR$
$94B(IAJ0H@΁<0ҡ3rRH2A	9igyő,MՕm噮J@,0Hi2`Є %1Y4(R9 )
H) !Ҝœ!9!%9N!@ 'MPJ)M%90H`20gaN2`@!@9igyő,MՕm噮{Ȁ@
,c*cBC I<$ЀL@
)Qe”rDh`HJD)R!!R(8$!9Cs" 2	!^0G4O4UWu_8go
9CSBЄ``L0RB```
rҜ$1$rœ!		9C8rʜs rjA #$!)B@œ!)
9C821S
9igyő,MՕm噮[J@œ!))CD0@ gaN™0,! $!	Bs I)B@NZ*)C0!LB3  '
3	BI8ͻ`(dihlp,tmDr!L`HB 0! 9Cs0':M !!PrB` V+C5!)CSR!LI`@N*O
9igyő,MՕm噮;́@NB2@)C0H9	BT„AB '!9B	 @erRBu V;C5!)CSR!L`I !Pj!@ '78y±<ӵ}gJ	BT(AB eaœ	@	9A0!Ag !!C@N*CA
rji  0eaC@œ!)	9,!p0^0G4O4UWu_8g")CT(AB eaœp9e0$Cg !!P@N0!P:$9i5PCHB20e!@ ea”`

! d9igyő,MՕm噮@NB2@)C0@B)CTʄAB '@! *G		Bsœ0H@A ':30ZB!$!LB2 20gaJC@ȉc„AB '78y±<ӵ}c1)CT(AB ea˜@ !
JBRBH20'AB gaB80PHA	IBBHB20e!@ gaJB80PH2)Grj/z?#Y'+ۺ/3]
P@9`R!	 !0rBDa9A	QppR˜`	ATD
5A'3F)!r!!9BcP@9
p`S@ G8B@ '78y±<ӵ}OP)9Q!J!@	!,!!2 0$@)9C`HJ!A ,!
			!)K0(!9 sa@ ' ePfB(B(HBB!80I@dP!ڋ޼H扦ʶL=Ad@ 'E$`3:	 9ga 2H9A$RA		@ʘ0  '
9id@p*	h"@ʘ N h@ %"
^0G4O4UWu_8go@NZ-!@ '78y±<ӵ}㹾}	ZB@NZYoCq$KDSue[cyks}

9i ڋ޼H扦ʶL$rjA9igyő,MՕm噮+(HՂrj/z?#Y'+ۺ/3]7;SP	!䤵B@NZYoCq$KDSue[cyks}{	
ru g@NZYo=r V{q֛wPQZ^Y~a\6ivq^y	
!#%')+-/13Q 
I89igyő,MՕm噮
r*!V{4'ڋ$rj/4 9	9i!Je:rrj/z?#Y'+ۺ/3]7.B!0
9iCBI8AB '<rb !d	rb V{q֛wP0!LBa@N$yHB 0e!@ eaœP@@00 !	@#ڋ\ V{q֛wP V{!!10
rRyH9igOHBrj/zC`I8ͻ`(PI8ͻ`(dihl!@ 4$ڋ<$rj!1aa4Rrj/Z &^# V{q֛wP V{q֛wPC!@ '78y±<ӵ}4I V{q֛wڋ޼H扦ʶL8 @! V{q֛wϡ V{q֛wPBAB '⬷9igy'(@ '78y±<ӵ}" V{q֛ڋ޼rj/z?#Y'+ۺ/3]7rj/z?ZP@NZYoCq$KDSue[cyk;ڋC 'BZkiiiP@NZYoCq$KDSue[cykrj/zs V{q!h5M4M4M4
I8ͻ`(dihlp,tmP@NZYonrj/ iii&A9igyő,MՕm噮m
I8m@NZ4M4M4M&(^0G4O4UWu_8gY(@ '79igZ4M4M4Mڋ޼H扦ʶL
^6@ 'BZkiii V{q֛wPrj/z9qqrj/z?#Y'+ۺ/3]C9igA
I8i@NZYo888nrj/z?#Y'+ۺ/3MC9igA
I8i@NZY888B@NZYoCq$KDSue[cye(@ 'w^4@ '7sqIP@NZYoCq$KDSue[cye(@ 'u^5@ '7sqMPI8ͻ`(dihlp,4^u{ڋ޼^ @ '7WP@NZYoCq$KDSue[cy_(@ 'q^5@ '79igy߂B@NZYoCq$KDSue[cy](@ 'o^5@ '79igyrj/z?#Y'+ۺ/3B9igmÖ0@ '79igI8ͻrj/z?#Y'+ۺ/3B9igMÖ0@ '79ig9
I8ͻ V{q֛wP9ipڋZ^Prj/zTB '78y±A9ig9Ik@9igI8ͻ^ @NZYoCq$KDSue[crj/z>`@JD9i4{ׂrZrj/z?A9i9igyő,Mrj/z?#Y'+B9igy/0@ %	I2`1 VZ+tB89irJ'c V[ýW^0G4)(@ '78y( V{q֛C@ V{ec-(@ '6Xks8!½Nh3	@ '{I8ͻ`(diRP@NZYoCq$KDSueQ(@ '		""$PHg`( `$D@"@` Vký{+(@ '6Xk`$ʽN !@ '{I8ͻ`(diRP@NZYoCq$KDSueQ(@ 'M
@B(Ѐ !JBP( 2^0c
I
Zkm)0A 'lG	0 p9igyő,M

I8ͻ`(dih,
Z-I0&@aP(#	B!@ eI2`1 V
OI8…'^09igyő,M

I8ͻ`(dih,
^$33 3	B!LM !&A 2^0

I{$^!@ ' !PJ)B9i2@ '78IA9igyő,MՕEڛMXB@B@!2	B
	!@ 'ʀ1WP@NZ-{-9ig-O	BRJ)P@NZI8ͻ`(diRP@NZYoCq$KDSueQ(@ '@		P&0R C3`)C@NZc1ZZ$rj/`@NBRJ)rje@NZYoCq$Krj/z?#Y'+B9ipH9PH0A 2œ!@HrjcqՂp)9,$4@HRd:y`3$J%rjoڋ޼H&^0G4O4UWrj< 
!C9C!L0@ eI2`1 V½WC(930A0Hp`8!	!9!`@NBRJ)rje@NZYoCq$Krj/z?#Y'+B9iW
 ! 9C!L0@ eI2`1 V½wÁ@Np(!C	@ 	!4P@CB(eB8B@NBRJ)rje{u]EA@ 'ZkVZzν{]A9)I8ͻ`(dih,
^9B4@(`<P00F` !A '1WP@NZ-^)G200##P !!)CRJ	K7`LAANHRrj/M9I8s9I8k@B@N
rj/z?#Y'+B9iwSA0@!B`H 	B` !
@NZ
{怒Z
R1ea`@N™!9')CS&0!J)R(@ 'V{o
&0
@ 'vpJI#;½u]4rj/!d V{q֛wPTZkZAAB '7ڋ޼H&^0G4O4UWrj/'4B@
3`@Y T^m!@ 'ZkRP	!^Z V{q֛wPҤڋ޼H扦ʢP@NZل+,!A ,I p#9S(ڋ
:2Zk	
r^=@ 'V^0G4)(@ '78y( V{qF 19OTЀ@N!($@Nj¡T^m!@ '9igyԠZ V{q֛wPҤڋ޼H扦ʢP@NZř2L!$
F !@2 s@A2I	@ '
I8۠C@N*rj/z?A9i2\	4@ ' '
I0Irj/rڋAN V{q^0G4O4UWrj/!@Np( 299
B@N V{qAT^Prje@NZYoCq$Krj/z?#Y'+B9i0@ RYB@$9 C0@Irj/6 ڋ޼jP@NZI8ͻ`(diRP@NZYoCq$KDSueQ(@ 'LB
9%	R0BP0rcf39` Irj/6 ڋ޼jP@NZI8ͻ`(diRP@NZYoCq$KDSueM(H^Q04CR)$,hfsp ^m!@ '9igyԠZ V{q֛wPҤڋ޼H扦ʊPڋhrC89͙F8Rڋ
yrR V{q֛wA
I9igyőƁ@NZ'I8ͻ`(dihl)!3@ 'J( s(9R3		` )M@,aH)I8ۀa9i@NZYo5(@ 'V^0/( D4'tHrf"R V{q֛wPD(0@@@đ,MՕm噮
20G  
"a1 $0@@  @1H$`Q<G4O4UWu_86O#)b@#)H

1q$KDSue[cyk~%ĀE1D D C@0 @0@@E"ƀ`$	0@@
@@aq44MG4O4UWuđ,MՕm噮8eY$$C$H9id  dihl#Y'+ۺ/3]7;:(q$2
101MsL4@@u8AhAAXAH)AA`CI8A#A0@1F#Yg	AaA  	IA $)AA$II$	  dihlp,tmx.u8&A01Ac#YApAAfB`8AA@CI$IAA@C)A$@(	   H q`h4  dihlp,tmx.u8"` d@HAeYeAPA8drAbA)AbAYJ(G1 H1$đ,GRL 2	`( ,K(q$KDSue[cyks1đqQ,@đ  I$IR   r0@@I`@ ( R ( đ,3  3	0@@$@ 	`8 G4đ,MՕm噮;H0 qQ$@Q  I$IR   r0@@	A   r   đ,3  30G,$@1$ 0 đ,M q$KDSue[cyk1cq1(@@ $I$ r   QD  1 10q$K 8 3 8đ,I$ 2 0 G4đ,MՕm噮;H0 qqq q$K  3   r  I$I20q 1 H I"   Q qqh$  dihlp,tm8AA8Ap(8(A8yAgA`AA#A@AA@$Id`(Ac)A$@A#8D$  A#@A`A08H
@@y.bHxyG@ApfHA@A@$IA$I$tc1A$8AbHi  dihlp,tm߸h#Y#Y"qcpd HA$9A$IcI$	 ABb$I$IG4O4UWu_8go\r4\
đ,	,8ϑ`8Oq$   H$$I
(A@IC$I$IG4O4UWu_8go\r4\
đ,,8`8qq$$$ 8ʲ,!,K$Q    1 I$I$  dihlp,tm߸h#YcpI"A9AP$hq 
$IR, I$ ID1`G#B@@<đ,MՕm噮
<1q$KSL<$0ΓL Hs$@@I ,K,Kđ$    1 I$I$  dihlp,tm߸h#YYAqrHCF)APeYFeY  $0A$	Ab@$I$8y±<ӵ}bArP   $QdBF	Re	G  d	 AaDpY"A8%Y&AAaHcHi  dihlp,tm߸hh @@ "@HR @q($I$HCeYE%C)&a%q$K H" Hđ,@@#Aq  $HF$$đ,MՕm6p}7xz^
@@ @@@@8DA DE q$đ,ME @Ȥ  	0HH(
đ$,˲,RD @Ȥ H HH(
đ$G4O4UWu` 
`H I q$KDSue[cy
H39đ$G4O4UW4pG4O4UW=2hm۶đ,M<G4O4UWu <3	 $I$8G4O4UWu_8`8pyٌ
@@I2q$KDSue۠m۶mHŤ#D<$D4H "@@w|^@A BCDEFGHIJKLMNOP;gperftools-gperftools-2.18/docs/pprof-vsnprintf-big.gif000066400000000000000000003045611513545575200233720ustar00rootroot00000000000000GIF89a{???___!,{I8ͻ`(dihlp,tmx|pH,Ȥrl:ШtJZجvzxL.zn|N~
H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜIM!@NZY2(%(@ '7P V{q֛wPB#0 '
rG1`)!r@ G8B8BHB3$A%'9BS
r*Cv €@NZYoCq$KDS
IL!I„) rBiL 08 ڋ޼H扦ʶL@!4 `rDHi`y$B(XB`B@rJR `Bd QBe	Se@NZYoCq$KDS	
If	ǀ@
@
 8Drڋ޼H扦ʶLPsB 'HuBprDI21a9* ,IA$RA
rR
9@$Rrj/z?#Y'NP@NZe LbR0 8CRR^0G4O4UWu_8go!A`I41I8}H!@ 'Dcarj/z?#Y'+ۺ/3]7!@ 4$ڋ<$rj/v V{q֛#'$	9iv@ '+!caarj/z?#Y'+ۺ/3]7PIO9igy0^oAkM4
B9CI61)$!A 'ֆr V{qֻrj/%d`1a6A!@ '78y±<ӵ}	rj/zs`I8֚i4B@rj 1FA$ ,@ 'ֆ0 V{qֻrj/`1a6A!@ '78y±<ӵ}	rj/zs`I8֚itB@rj/H1VA&)BRB@NZYoI1aڋ޼H扦ʶL#$rRyBHI8o!@ '|CZka
!@ g9iu̽@@NZm
!{'4!^![Gcaarj/z?#Y'+ۺ/3]7PIe
́(D9
@И(PH h@ '0r!r 	$A '@РBA @H29A̜39C`H 0A ' R0Ik@NzB0r9
	SaHHiN Ʉ	N99$(1H9Pf$YH h		 1xI&@ <A '
9igyő,MՕm噮G(Hr@9!N!R8B(B$&8SBb !F	M	M tBI	!)S8B20	!@ %B
99!1G	0`NaJ$rAJtBNZUDBsAB`$0HI!,	L@`$0N	s4M0hBp`!̉)K9igmI8ͻ`(dihlp,tmx>BAB '!@H4P@p P!!@8$@ 2	aLQ9!!R@0)D!	Lc!L!$y'@ '#P	BAB '!9B9	iNpBBr!H@`(HiBsN9B!F0	9IcP40H	9C821Ss B@B	)Cs03jZP	BA   @!!
!@ AaBCJ0B	``€@a @NZYorj/z?#Y'+ۺ/3]7PIga%%4Cs"(#r@9CsB
P@)3'R`g0rRiB Մ@ )CSr!9%d)9i
0DC4 pdg0 p  20eaC@N™ 0D0IF@N9B I8mC@NZYoCq$KDSue[cyk
9!B:!@ '0!B &"IsNxB@NB(	@	N$ʨsBH@ 30eaC@œsQ<	9)ANZrR#B)EA ӄ@	!$9	!8 BB4!)Cr!	 	I	!QAB '⬷
9igyő,MՕm噮G(H2fJ(H#0CTB sdc)!r4@$@# It r@ 'BB)0hp@ gaœ!9 Hʀ@NZ'Q@ '4B	  	!X rB(tx!!@ ea#0Aa€@N
	!R+9igmI8ͻ`(dihlp,tmx>BAB ''3CUBA!B3!!Bt r30%$@  CJ$@&䤳N08(A gaœ!9sH@NZ%S
@ '2C	 BK!8!%ΘP!!LB  hrYB:a9igmI8ͻ`(dihlp,tmx>BAB '&CCUB$ 3Ct  #I tx !!9gaJ(H9AG0H	98B@Ig	!@ (!P	@œs9<^`BH5rR`BH4@a9B8SB€@N:PILB`@”!	9A(	@ 'B9@ '⬷
9igyő,MՕm噮G(H`hJ sfaC( sP$
	 30!) H"!$yB@s H"DG1	aigH!
BT !20sN	G!@ '*
9!A`I8AB '7ڋ޼H扦ʶL"4B)
	A '7	kGcaaX#ڋ'$	9ig0^0ܠ V{q֛wPBAB ''ڋrj
!`1aQ9CIs ڋ< V{q֛wpB@NZYoCq$KDSue[cyk
9)!^8 V{oc10NB@NZ20*Ȅ 2` V{q{rj/z?nPI8ͻ`(dihlp,tmx>BAB ''ڋrj
!`1aM
!@ g9iu̽@@NZYI8ͻ`A!@ '78y±<ӵ}	T(HI0
	@4 s 	)rH 9`! B@NJ
"S%@9
"34@@JsI&9
r``80D	9i2ANZr`p JsI&	N i&HIH9PƜP	"C'drj/z?(A!@ '78y±<ӵ}	T0'	!@
@0P`P`gJHR"d(!)	ĀN9DȀQB@Hi1`B@	)	!FL@` sHiAB g 4I(ZkU%A$!948P0H(`B(0Hi2`Є %1HB!F! 	$!V{q֛wA	
9igy,MՕm噮G(H3	!@
R<$ BR4!	 
!@ 'B0Є(!L!$y'@ '#P	BAB '!Br!̉` rD0II!9%ANH@ ga	@RJ)0394!jB HҔ!)C9CS2ڋgrRr`@BC@”!	9Qg '
39igy V{q֛wPBAB '=!$
BtB#0 22AaL	KBHYB҄L!$%4!ԄH!&`1r 9)=! DK0$!
BT !2ښν&R3	CR!L`)KcЄ`9igy V{q֛wP!V{q֛wPH@NZgZk@
p&R(A ڋ޼H扦ʶL
}`Z+A) 2p@!p@)IA@NZYoCq$KDSue[cyks}{>H@NZgZk,$Dƥ9igyő,MՕm噮 9iZkֲq VKϸ5@ '78y±<ӵ}㹾$@ '4@ '7^0G4O4UWu_8go
	I8ͻ`(dijP@NZYI8ͻ`(dihlp,tmx|ڋ޼H^! V{q֛wP	I8ͻ`(dijP@NZYo9igyő,MՕm噮
 V{q֛wPԠڋ޼$rj/z?#Y'+ۺ/3]7;$@ '78A9igy0H^0G4O4UWu_8go$CBZkY V+ýQ
%2($@4 V{qC@NZ%10ð
:$TZgZU@NIAN  R`&p 3$#! S! (RJ !@ !:KrB`)CB@BJ9iW
0 ӄȜ!C	!!3!r sœ2rjuZkUU$rsΙ`9i4@02@!8J8!JHBH)
"!9A0@ 'ZgVUUUUUQ!#BA	@ 4$ڋAki@#@ !@ '9	!PJ<3Pkt! 䔃A)#@tZk9igyőDRsΉ`0IA*Q9Q80(Q:M@R(@ 'V^Jd@  !9jx 3	a@ND)r V{q֛wPFNV^fnv~'/7?GOW烈;gperftools-gperftools-2.18/docs/pprof-vsnprintf.gif000066400000000000000000000745161513545575200226370ustar00rootroot00000000000000GIF89a"___???wwwooo!,"I8ͻ`(dihlp,tmx|pH,Ȥrl:ШtJZجvzxL.zn|N~o@ 'vr-!I"^0G4O4UWu_8Fb V;trj/z?#Y'+ۺ/d
I{9)M$TkU @ ' @ '78y1DI9)-3ZkpF@NZG@NZYoCq$KDSue[a @B0ʀ(p!p
8`	!BA8 9C!@C	4(!H9igyő,MՕmvPF!		@JP@	TA9G#HB%@@@NZYoCq$KDSue[a   Hd2H A $!RJR@	) V{q֛wP9igyő,MՕm
rNU`B V
h,Ѐ@NZYoCq$KDSue[c
	@
	2PJ)EP@NZ-H$$,	A '78y±@a	rj/!gZ A	,^0G4O4UWu_86%P	PB% Kx@
8@
`RA '%2@%@NZYoCq$KDSue[c

( J	P$QH%
%H f@ '78y±	@@NdJ H$2H AB@ 'ij@NZYoCq$KDSue[
 %99@@așs3&g@ '78y	@P䔇Pda@rC(c0aڋ޼H扦ʶ'4J C@(3€@PJaa (0@* A(%@ ' 
(9AI8ͻ`(dihlp\BA%CR)C	E@I0H $A`
I)Q`B0I8ͻ`(dihlp, V{q֛wP`@N4h9rj/z?#Y'+ۺ/C9ig9O0@ '	s99igyő,MՕmڋ|r0sN V{q֛wPQZ^Y~a\6ivq^y	
 ";gperftools-gperftools-2.18/docs/pprof_integration.adoc000066400000000000000000000115561513545575200233470ustar00rootroot00000000000000== pprof integration

:reproducible:

gperftools was the original home for the pprof program. This program
is used to visualize and analyze profiles (CPU profiles, heap
profiles, heap samples, set of thread stacks, etc.). The original
pprof was written in Perl. As of this writing, the Linux distros are
shipping this version of pprof. Meanwhile, pprof was completely
modernized and rewritten in Go. The Go version is a much better
one. We've been recommending people to switch to the Go version for a
number of years and starting gperftools 2.17 we no longer have the
original pprof.

You can get the Go pprof binary by running:

  % go install github.com/google/pprof@latest

The binary will normally appear in `$HOME/go/bin`. So you may want to
add it to your `$PATH`.

The main documentation of pprof can be found at
https://github.com/google/pprof/blob/main/doc/README.md

On this page, I'll point out some helpful integration aspects.

Here are the kinds of "profiles" that gperfools can feed into pprof.

=== CPU profiling

CPU profiler is provided in a distinct library: libprofiler. It's C++
API is in `gperftools/profiler.h`. You can invoke
`ProfilerStart()`/`ProfilerStop()` to control it. Or you can have
libprofiler automagically profile the full run of your program by setting
`CPUPROFILE` environment variable.

See link:cpuprofile.html[documentation of CPU profiler] for full
details.

A general description of how statistical sampling profilers work can be
found in this nice blog post: https://research.swtch.com/pprof.

We produce a "legacy" CPU profile format. The format is described
here: link:cpuprofile-fileformat.html[].

=== Heap sample

libtcmalloc supports very low overhead sampling of allocations. If this feature is enabled, you can call:

  std::string sample_profile;
  MallocExtension::instance()->GetHeapSample(&sample_profile);

And you'll get a statistical estimate of all currently in-use memory
allocations with backtraces of allocations. It will show you where
currently in-use memory was allocated. Heap sample can be saved and
fed to the pprof program for visualization and analysis.

At Google, this feature is enabled fleet-wide (and by default), but in
gperftools, our default is off. You can turn it on by setting the
environment variable `TCMALLOC_SAMPLE_PARAMETER`. However, please note
that libtcmalloc_minimal doesn't have this feature. In order to use
heap sampling, you need to link to "full" libtcmalloc.

The reasonable value of the sample parameter is from 524288 (512kb;
original default) to a few megs (current default at Google). A lower
value gives you more samples, so higher statistical precision. But a
lower value also causes higher overhead and lock contention.

Our sibling project, "abseil" tcmalloc, also supports heap
sampling. Implementation has evolved a bit, but this is fundamentally
the same logic. In addition to sampling, they also have allocation and
deallocation profiling powered by the same sampling facility. Their
docs are at:
https://github.com/google/tcmalloc/blob/master/docs/sampling.md.

Go has similar feature called heap profiling. Go's heap profiles
combine information about in-use memory and all the allocations ever
made. It is similar to gperftools' link:heapprofile.html[heap profiler] but works
via sampling, so it is low overhead and runs by default. You can read
about it here: https://pkg.go.dev/runtime/pprof. Approximately every
512k bytes (value of runtime.MemProfileRate) of memory allocated, Go's
runtime triggers heap sampling. Heap sampling grabs backtrace, and
then updates per-call-site allocation counters. The heap profile is a
collection of call sites (identified by the backtrace chain) and
relevant statistics.

=== Heap Growth stacks

Every time tcmalloc extends its heap, it grabs stack trace. A
collection of those stacks can be obtained by:

  MallocExtension::instance()->GetHeapGrowthStacks(&string);

and fed to pprof for visualization and analysis. This kind of profile
gives you locations in your code that extended heap (either due to
regular usage, leaks, or fragmentation).

Heap growth tracking is always enabled in full libtcmalloc and is cut
off from libtcmalloc_minimal.

=== Heap Profiler

See link:heapprofile.html[Heap Profiler documentation]. Note that the
heap profiler intercepts every allocation and deallocation call, so it
runs with a much higher overhead than normal malloc and is not
suitable for production.

=== HTTP interfaces

The more commonly used pprof integration point used at Google is via
HTTP endpoints. Go standard library provides a great example of how it
is done and how to use it. https://pkg.go.dev/net/http/pprof documents
it.

gperftools doesn't provide any HTTP handlers, but we do give you raw
profiling data, which you can serve by whatever HTTP-serving APIs you
like. Each profile kind (with the partial exception of heap profiler)
has an API to obtain profile data, which can be returned from an HTTP
handler.
gperftools-gperftools-2.18/docs/spanmap.gif000066400000000000000000000204421513545575200211060ustar00rootroot00000000000000GIF89aL???___!,LI8ͻ`(dihlp,tmx|pH,Ȥrl:ШtJZجvzxL.zn|N~sANZYoCq$KDSue[crRjZk@9igZڋ
ZkP@NZ(@ '|Zk V{qAk	
IAZk^mZk
rj/7h@9igZڋ
ZkP@NZ&(@ 'ZkV V{qAk5
I8ߠ^mZk
rj/7h@9igZZkZP@NZ(@ '|Zk V{qAk5
I8ߠ^mZkmrRjZk@9igZڋ
ZkP@NZ(@ '|Zk V{qAk	
IAZk^mZk
rj/7h@9igZڋ
ZkP@NZ&(@ 'ZkV V{qAk5
I8ߠ^mZk
rj/7h@9igZZkZP@NZ(@ '|Zk V{qAk5
I8ߠ^mZkmrRjZk@9igZڋ
ZkP@NZ(@ '|Zk V{qAk	
IAZk^mZk
rj/7h@9igZڋ
ZkP@NZ&(@ 'ZkV V{qAk5
I8ߠ^mZk
rj/7h@9igZZkZP@NZ(@ '|Zk V{qAk5
I8ߠ^mZkmrRjZk@9igZڋ
ZkP@NZ(@ '|Zk V{qAk	
IAZk^mZk
rj/7h@9igZڋ
ZkP@NZ&(@ 'ZkV V{qAk5
I8ߠ^mZk
rj/7h@9igZZkZP@NZ(@ '|Zk V{qAk5
I8ߠ^mZkmrRjZk@9igZڋ
ZkP@NZ(@ '|Zk V{qAk	
IAZk^mZk
rj/7h@9igZڋ
ZkP@NZ&(@ 'ZkV V{qAk5
I8ߠ^mZk
rj/7h@9igZZkZP@NZ(@ '|Zk V{qAk5
I8ߠ^mZkmrRjZk@9igZڋ
ZkP@NZ(@ '|Zk V{qAk	
IAZk^mZk
rj/7h@9igZڋ
ZkP@NZ&(@ 'ZkV V{qAk5
I8ߠ^mZk
rj/7h@9igZZkZP@NZ(@ '|Zk V{qAk5
I8ߠ^mZkmrRjZk@9igZڋ
ZkP@NZ(@ '|Zk V{qAk	
IAZk^mZk
rj/7h@9igZڋ
ZkP@NZ&(@ 'ZkV V{qAk5
I8ߠ^mZk
rj/7h@9igZZkZP@NZ(@ '|Zk V{qAk5
I8ߠ^mZkmrRڋ޼H扦ʶ ^|C9S(@ 'A{ofA!@ 'brΙB9iϐs
9igy
IsP@NZYo^rj/!s6A9igqڋi9	^LC9,2

IsP@NZYo^rj/!s6A9igsIsP@NZ2B@NZYorj/!' V{q֛ڋe9MP@NZY8&(@ 'rYB9iːs9˲rj/!' V{q֛ڋcIP@NZYorj/!% V{19,ڋ޼^,C9K(@ '79i1ڋ\^,C9(@ 'brڋ޼K V{19,ڋ^0cLrj/z`@NZ 3I8`19igy0@ '1^9@ '1c V{q֛ڋA9c V{oc
rj/z~a@NZc)I8w@NZc1&(@ '79i10@ 'ڀ1^{O V{q֛kcMP@NZYo~rj/c,a@NZc%9igy0@ 'ڀ1^<@ 'ڀ1c V{q֛rj
c,a@NZc%I8;9i10@ '7^0crj/zs V{mcrj/
c,a@NZYo=I5`19igy0@ 'Ҁ1c V{q֛k^0ڋ޼{	^0ڋ޼K V{ic1

I8y@NZcrjc`@NZYorj/
c V{q֛w
rjc1FA9igyI5`o@NZclI8ͻP@NZcrj/zNa@NZc1*(@ '7K^05ڋ޼^07@ '7^0crj/z>a@NZc\rj/ V{q֛wϡ^cUP@NZYo)I3`k@NZcLrj/z; V{Aڋ޼c Vký{/
I8{!@ 'ʀ19i7{mI8ͻP@NZ
rj/za@NZ
{,(@ '7^03@ 'ֆ{
I8ͻ Vký{뺮뺮&(@ 'ֆ{^ V{q֛wrj/ V[ý^

Ikýu]u]u] Vký{/
I8{!@ '{o
^ Vkrj/zp뺮뺮.
I{^}4{MP@NZ
I8ͻ VKý{뺮뺮.(@ '{^ V{q֛wC@NZ
$(@ 'ڋ޼A9i3{i뺮뺮rji{uA9igy0@ '{^ VKrj/z?p뺮뺮뺮rji{uA9igy
9i4{eZ V{q֛w=(@ 'V{^u]u]u] V+ý{rj/z' VKý{/(@ '^
I+ýu]u]u]pڋ޼{
p
^(@ 'Vڋ޼JP@NZmڋ޼{
pڋ޼
p
Z(@ 'V^rj^S(@ 'V{^^[(p
Z(@ '6^ЂrZv^[(@ '6XkZV^c(@ 'V{kB9i9igy̠`9igy
I
ZkUA9igy
IP@NZkI8ͻ䤕k-I8ͻP@NZmZk

I8ͻPI
`9i9igy`9igy
I+
ZkeA9igy
Ik
`m9i9igy`
I8ͻP9!^uAڋ޼䤵,AN	2@)2^ @ 'AN	3ڋ޼{9r	9igma3@ '7^C!@ '4,AN	2(^0B@N
9g^g(	t 'rj/ 'rj/z; 	9a3@ AJڋ޼@	9'RB '7^CAN9!V{q9!V{q֛w V@N
)a9)
I8ͻ`HAAN0	9rj/z3@N
`9iga9igyr	9)rB Aڋ޼Ia9'rJ^g(H	 %rj/Z`@NZYo J9a9%r^0 g@	9aSB '7^CAJ)!V{q:rj/z9!s %rJ@I8ͻ`AAN0H	9rj/z9d@N
B9igC0@ '7[P)!0H	0	ڋ޼@NB@NZYo޽@N
BI8
B!@ '7_P  (! S0	ڋ޼d@NB@NZYo@N
BI8
B9igy?	BRB@NBT @NZYo
2@ !P
B9igy@B@NZYrj/z9!(!J !9'rj/z?zP9Crj/z3^!@ '7gPSB 'R0I!V{q֛wЃB@N ^
9gI8Mqq	BJC@N9igyC(䜁Rrj/z;	ڋANZI8ͻPS(R*!`3@ '7!9iWB '7^C9i1
I9igy
rrjo0H	ڋ޼"ڋ޼{
^0_(@ '^
RI8ͻ`(NP@NZ
I8ͻP@NZcrjo@NZYo rjoI8ͻ`(ZP@NZ
I8ͻP@NZcrjo@NZYo V{rj/z? V{rj/z5 V{Ac| V{q֛w/(@ '^0/(@ '^k(@ '1B9i7@ '7_P@NZ
I8ͻ`(^P@NZ
I8ͻP@NZcrjo@NZYo V{q֛wP V{q֛wڋ޼A9i7@ '7xA9i7@ '7^C9i1
	)RJA@NZYo V{q֛wPSB9igy
I `1P@NBR V{q֛w/(@ '^0/(@ '&Zrj/z5 V{Ac|3J)9igyrjo@NZYoCr
B4@ '7^C9i1
9CR V{q֛w/(@ '^0/(@ ' Krj/z5 V{Ac|3J)9igyrjo@NZYoCr
B4@ '7^C9)$bj0@ ',Cȁ@N*rj/z%ڋ޼%BNڋ޼{
#pڋ9x"@ '9igyrR
B$P:a@NZYoCrRDB)J% V{q֛wB2ZUUUU!L3@ '7_P@NZ J%I8ͻ`(^P@N(J%I8ͻP@N*@!*rj/2  9I8ͻ @)9igy
II!P*rj/z5 tdڋ9$d)rj/z! JI8ͻ`(^P@N
R V{q֛w4@ ',CiBRJ	rj/z%2@ '7xA9)	g@I8ͻP@N'd(ڋ8"9I8ͻ @	rj/z? @8!2@ '7^C9!!
I8ːQ$t^
I)Ze@NZYoCrRpH(&$S) V{q֛wڋ޼A9i7@ '7xA9i7@ '7^C9i1
I9igyrjo@NZYoCrjo@NZYo޽rj/c/ V{rj/zڋ޼ڋ޼{
^0_(@ '^
I9igy
I9igy
I `1P@NZ
I8ͻ V{rj/z? V{rj/z5 V{Ac| V{q֛w/(@ '^0/(@ '^k(@ '1B9i7@ '7_P@NZ
I8ͻ`(^P@NZ
I8ͻP@NZcrjo@NZYoϜ V{q֛wP V{q֛w 'N^%rj@NZYo 'J^0/(I9igyő,MՕm噮ET.MNUn]eVmu}0Pp1Qq2Rr33";gperftools-gperftools-2.18/docs/tcmalloc.adoc000066400000000000000000000640251513545575200214130ustar00rootroot00000000000000= TCMalloc : Thread-Caching Malloc

:reproducible:

== [#motivation]#Motivation#

+[alk: Update from Dec 2024]+ Wondering how to update this document
from beginning of 2000-x I am choosing to keep this original
motivation writeup just below. Do keep in mind that referenced glibc
versions are now long obsolete. And amount of time per malloc call is
far from correct anymore. And the description is for 32-bit
computers. Still, I am choosing to keep this text intact, to help
people see where tcmalloc came from. "I" below refers to original
author: Sanjay. See at the end of this paragraph for some commentary
relevant for today.

'''''

TCMalloc is faster than the glibc 2.3 malloc (available as a separate
library called ptmalloc2) and other mallocs that I have tested.
ptmalloc2 takes approximately 300 nanoseconds to execute a malloc/free
pair on a 2.8 GHz P4 (for small objects). The TCMalloc implementation
takes approximately 50 nanoseconds for the same operation pair. Speed is
important for a malloc implementation because if malloc is not fast
enough, application writers are inclined to write their own custom free
lists on top of malloc. This can lead to extra complexity, and more
memory usage unless the application writer is very careful to
appropriately size the free lists and scavenge idle objects out of the
free list.

TCMalloc also reduces lock contention for multi-threaded programs. For
small objects, there is virtually zero contention. For large objects,
TCMalloc tries to use fine grained and efficient spinlocks. ptmalloc2
also reduces lock contention by using per-thread arenas but there is a
big problem with ptmalloc2's use of per-thread arenas. In ptmalloc2
memory can never move from one arena to another. This can lead to huge
amounts of wasted space. For example, in one Google application, the
first phase would allocate approximately 300MB of memory for its URL
canonicalization data structures. When the first phase finished, a
second phase would be started in the same address space. If this second
phase was assigned a different arena than the one used by the first
phase, this phase would not reuse any of the memory left after the first
phase and would add another 300MB to the address space. Similar memory
blowup problems were also noticed in other applications.

Another benefit of TCMalloc is space-efficient representation of small
objects. For example, N 8-byte objects can be allocated while using
space approximately `+8N * 1.01+` bytes. I.e., a one-percent space
overhead. ptmalloc2 uses a four-byte header for each object and (I
think) rounds up the size to a multiple of 8 bytes and ends up using
`+16N+` bytes.

'''''

+[alk: Update from Dec 2024]+ tcmalloc (now gperftools) has evolved a
lot over last 20-ish years. Back then it was one of the first
production-grade malloc that used per-thread caching. This days
per-thread (or even per-cpu) caching is widespread. Typical C++
programs tend to allocate and free memory somewhat frequently and
those small allocations are generally kept fast and avoid any locks
(in most cases). Most of gperftools evolution was on getting those
common cases even cheaper. Others improved too. glibc, while still
being somewhat slower than gperftools, is a lot faster than it was and
also avoids locks in many of those common case allocations.

gperftools on modern systems with efficient "native" thread-local
storage access (i.e. GNU/Linux, most BSDs, even Windows, but, notably,
not OSX) takes just a couple dozen cheap instructions for allocation
or deallocation, which is better than most competition. We're talking
in the ballpark of just a couple nanoseconds per operation on modern
fast out-of-order CPUs in this fast-path case (all caches are hot
etc). I.e. compare to mid-tens of nanos per malloc/free pair 20 years
ago (!)

Also, the reader should be aware that another descendant of the
original tcmalloc is now available at
https://github.com/google/tcmalloc (I call it "abseil tcmalloc" due to
it's hard dependency on abseil). Its main feature is efficient per-cpu
caches (but it needs RSEQ support from fairly recent Linux kernels).

Another direction of evolution, particularly at Google, was increasing
focus on helping diagnose or prevent production problems related to
dynamic memory allocation. So there is debug version of tcmalloc with
some relatively lightweight checking against common bugs (like
double-free). So there is heap sampling that has low enough overhead
to be always enabled. There are relatively comprehensive statistics
available and more. "abseil tcmalloc" is doing even better than
gperftools in this regard.

== [#Usage]#Usage#

To use TCMalloc, just link TCMalloc into your application via the
"-ltcmalloc" linker flag.

You can use TCMalloc in applications you didn't compile yourself, by
using LD_PRELOAD:

....
   % LD_PRELOAD="/usr/lib/libtcmalloc.so"
....

TCMalloc includes a link:heapprofile.html[heap profiler] as well.

If you'd rather link in a version of TCMalloc that does not include
the heap profiler (perhaps to reduce binary size for a static binary),
you can link in `+libtcmalloc_minimal+` instead.

== [#Overview]#Overview#

TCMalloc assigns each thread a thread-local cache. Small allocations are
satisfied from the thread-local cache. Objects are moved from central
data structures into a thread-local cache as needed, and periodic
garbage collections are used to migrate memory back from a thread-local
cache into the central data structures.

image:overview.gif[overview]

TCMalloc treats objects with size +<=+ 256K ("small" objects) differently
from larger objects. Large objects are allocated directly from the
central heap using a page-level allocator (a page is a 8K aligned region
of memory). I.e., a large object is always page-aligned and occupies an
integral number of pages.

A run of pages can be carved up into a sequence of small objects, each
equally sized. For example a run of one page (4K) can be carved up into
32 objects of size 128 bytes each.

== [#Small_Object_Allocation]#Small Object Allocation#

Each small object size maps to one of approximately 88 allocatable
size-classes. For example, all allocations in the range 961 to 1024
bytes are rounded up to 1024. The size-classes are spaced so that small
sizes are separated by 8 bytes, larger sizes by 16 bytes, even larger
sizes by 32 bytes, and so forth. The maximal spacing is controlled so
that not too much space is wasted when an allocation request falls just
past the end of a size class and has to be rounded up to the next class.

A thread cache contains a singly linked list of free objects per
size-class.

image:threadheap.gif[threadheap]

When allocating a small object: (1) We map its size to the corresponding
size-class. (2) Look in the corresponding free list in the thread cache
for the current thread. (3) If the free list is not empty, we remove the
first object from the list and return it. When following this fast path,
TCMalloc acquires no locks at all.

If the free list is empty: (1) We fetch a bunch of objects from a
central free list for this size-class (the central free list is shared
by all threads). (2) Place them in the thread-local free list. (3)
Return one of the newly fetched objects to the applications.

If the central free list is also empty: (1) We allocate a run of pages
from the central page allocator. (2) Split the run into a set of objects
of this size-class. (3) Place the new objects on the central free list.
(4) As before, move some of these objects to the thread-local free list.

=== [#Sizing_Thread_Cache_Free_Lists]#Sizing Thread Cache Free Lists#

It is important to size the thread cache free lists correctly. If the
free list is too small, we'll need to go to the central free list too
often. If the free list is too big, we'll waste memory as objects sit
idle in the free list.

Note that the thread caches are just as important for deallocation as
they are for allocation. Without a cache, each deallocation would
require moving the memory to the central free list. Also, some threads
have asymmetric alloc/free behavior (e.g. producer and consumer
threads), so sizing the free list correctly gets trickier.

To size the free lists appropriately, we use a slow-start algorithm to
determine the maximum length of each individual free list. As the free
list is used more frequently, its maximum length grows. However, if a
free list is used more for deallocation than allocation, its maximum
length will grow only up to a point where the whole list can be
efficiently moved to the central free list at once.

The pseudo-code below illustrates this slow-start algorithm. Note that
`+num_objects_to_move+` is specific to each size class. By moving a list
of objects with a well-known length, the central cache can efficiently
pass these lists between thread caches. If a thread cache wants fewer
than `+num_objects_to_move+`, the operation on the central free list has
linear time complexity. The downside of always using
`+num_objects_to_move+` as the number of objects to transfer to and from
the central cache is that it wastes memory in threads that don't need
all of those objects.

....
Start each freelist max_length at 1.

Allocation
  if freelist empty {
    fetch min(max_length, num_objects_to_move) from central list;
    if max_length < num_objects_to_move {  // slow-start
      max_length++;
    } else {
      max_length += num_objects_to_move;
    }
  }

Deallocation
  if length > max_length {
    // Don't try to release num_objects_to_move if we don't have that many.
    release min(max_length, num_objects_to_move) objects to central list
    if max_length < num_objects_to_move {
      // Slow-start up to num_objects_to_move.
      max_length++;
    } else if max_length > num_objects_to_move {
      // If we consistently go over max_length, shrink max_length.
      overages++;
      if overages > kMaxOverages {
        max_length -= num_objects_to_move;
        overages = 0;
      }
    }
  }
....

See also the section on link:#Garbage_Collection[Garbage Collection] to
see how it affects the `+max_length+`.

== [#Medium_Object_Allocation]#Medium Object Allocation#

A medium object size (256K ≤ size ≤ 1MB) is rounded up to a page size
(8K) and is handled by a central page heap. The central page heap
includes an array of 128 free lists. The `k`-th entry is a free list of
runs that consist of `k + 1` pages:

image:pageheap.gif[pageheap]

An allocation for `k` pages is satisfied by looking in the `k`-th
free list. If that free list is empty, we look in the next free list,
and so forth. If no medium-object free list can satisfy the allocation,
the allocation is treated as a large object.

== [#Large_Object_Allocation]#Large Object Allocation#

Allocations of 1MB or more are considered large allocations. Spans of
free memory which can satisfy these allocations are tracked in a
red-black tree sorted by size. Allocations follow the _best-fit_
algorithm: the tree is searched to find the smallest span of free space
which is larger than the requested allocation. The allocation is carved
out of that span, and the remaining space is reinserted either into the
large object tree or possibly into one of the smaller free-lists as
appropriate. If no span of free memory is located that can fit the
requested allocation, we fetch memory from the system (using `+sbrk+`,
or `+mmap+`).

If an allocation for `+k+` pages is satisfied by a run of pages of
length > `+k+`, the remainder of the run is re-inserted back into the
appropriate free list in the page heap.

== [#Spans]#Spans#

The heap managed by TCMalloc consists of a set of pages. A run of
contiguous pages is represented by a `+Span+` object. A span can either
be _allocated_, or _free_. If free, the span is one of the entries in a
page heap linked-list. If allocated, it is either a large object that
has been handed off to the application, or a run of pages that have been
split up into a sequence of small objects. If split into small objects,
the size-class of the objects is recorded in the span.

A central array indexed by page number can be used to find the span to
which a page belongs. For example, span _a_ below occupies 2 pages, span
_b_ occupies 1 page, span _c_ occupies 5 pages and span _d_ occupies 3
pages.

image:spanmap.gif[spanmap]

In a 32-bit address space, the central array is represented by a a
2-level radix tree where the root contains 32 entries and each leaf
contains 2^14 entries (a 32-bit address space has 2^19 8K pages, and the
first level of tree divides the 2^19 pages by 2^5). This leads to a
starting memory usage of 64KB of space (2^14*4 bytes) for the central
array, which seems acceptable.

On 64-bit machines, we use a 3-level radix tree. Note that, many
common 64-bit machines have limits on actual address space size. So on
x86 we use 48 bits of address and handle it by slightly-faster 2-level
radix tree.

== [#Deallocation]#Deallocation#

When an object is deallocated, we compute its page number and look it
up in the central array to find the corresponding span object. The
span tells us whether or not the object is small, and its size-class
if it is small. If the object is small, we insert it into the
appropriate free list in the current thread's thread cache. If the
thread cache now exceeds it's max_size_ amount, we run a garbage
collector that moves unused objects from the thread cache into central
free lists.

If the object is large, the span tells us the range of pages covered by
the object. Suppose this range is `+[p,q]+`. We also lookup the spans
for pages `+p-1+` and `+q+1+`. If either of these neighboring spans are
free, we coalesce them with the `+[p,q]+` span. The resulting span is
inserted into the appropriate free list in the page heap.

== Central Free Lists for Small Objects

As mentioned before, we keep a central free list for each size-class.
Each central free list is organized as a two-level data structure: a set
of spans, and a linked list of free objects per span.

An object is allocated from a central free list by removing the first
entry from the linked list of some span. (If all spans have empty linked
lists, a suitably sized span is first allocated from the central page
heap.)

An object is returned to a central free list by adding it to the linked
list of its containing span. If the linked list length now equals the
total number of small objects in the span, this span is now completely
free and is returned to the page heap.

== [#Garbage_Collection]#Garbage Collection of Thread Caches#

Garbage collecting objects from a thread cache keeps the size of the
cache under control and returns unused objects to the central free
lists. Some threads need large caches to perform well while others can
get by with little or no cache at all. When a thread cache goes over its
`+max_size+`, garbage collection kicks in and then the thread competes
with the other threads for a larger cache.

Garbage collection is run only during a deallocation. We walk over all
free lists in the cache and move some number of objects from the free
list to the corresponding central list.

The number of objects to be moved from a free list is determined using a
per-list low-water-mark `+L+`. `+L+` records the minimum length of the
list since the last garbage collection. Note that we could have
shortened the list by `+L+` objects at the last garbage collection
without requiring any extra accesses to the central list. We use this
past history as a predictor of future accesses and move `+L/2+` objects
from the thread cache free list to the corresponding central free list.
This algorithm has the nice property that if a thread stops using a
particular size, all objects of that size will quickly move from the
thread cache to the central free list where they can be used by other
threads.

If a thread consistently deallocates more objects of a certain size than
it allocates, this `+L/2+` behavior will cause at least `+L/2+` objects
to always sit in the free list. To avoid wasting memory this way, we
shrink the maximum length of the freelist to converge on
`+num_objects_to_move+` (see also
link:#Sizing_Thread_Cache_Free_Lists[Sizing Thread Cache Free Lists]).

....
Garbage Collection
  if (L != 0 && max_length > num_objects_to_move) {
    max_length = max(max_length - num_objects_to_move, num_objects_to_move)
  }
....

The fact that the thread cache went over its `+max_size+` is an
indication that the thread would benefit from a larger cache. Simply
increasing `+max_size+` would use an inordinate amount of memory in
programs that have lots of active threads. Developers can bound the
memory used with the parameter
`TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES`.

Each thread cache starts with a small `+max_size+` (e.g. 64KB) so that
idle threads won't pre-allocate memory they don't need. Each time the
cache runs a garbage collection, it will also try to grow its
`+max_size+`. If the sum of the thread cache sizes is less than
`TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES`, `+max_size+` grows easily. If
not, thread cache 1 will try to steal from thread cache 2 (picked
round-robin) by decreasing thread cache 2's `+max_size+`. In this way,
threads that are more active will steal memory from other threads more
often than they are have memory stolen from themselves. Mostly idle
threads end up with small caches and active threads end up with big
caches. Note that this stealing can cause the sum of the thread cache
sizes to be greater than `TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES` until
thread cache 2 deallocates some memory to trigger a garbage
collection.

== [#performance]#Performance Notes#

gperftools' area of relative strength is cases where per-thread caches
are effective. This is typically exercised by fairly typical C++ codes
that allocate relatively often and where object lifetimes tend to be
small-ish.

Both "abseil tcmalloc" and gperftools continue to have un-sharded
central free lists and page heaps. Which means that misses to caches
tend to be not so scalable compared to some competition.

This means that in some cases you may want to tweak thread caches
higher. Also if your workload has many threads that tend to be idle
for longer durations, consider using
`MallocExtension::MarkThread{Idle,Busy}`.

== [#runtime]#Modifying Runtime Behavior#

You can more finely control the behavior of the tcmalloc via environment
variables.

Generally useful flags:

[cols=",,",]
|===

|`TCMALLOC_SAMPLE_PARAMETER` |default: 0 |The approximate gap between
sampling actions. That is, we take one sample approximately once every
`tcmalloc_sample_parmeter` bytes of allocation. This sampled heap
information is available via `MallocExtension::GetHeapSample()` or
`MallocExtension::ReadStackTraces()`. A reasonable value is 524288.

|`TCMALLOC_RELEASE_RATE` |default: 1.0 |Rate at which we release
unused memory to the system, via `+madvise(MADV_DONTNEED)+`, on systems
that support it. Zero means we never release memory back to the system.
Increase this flag to return memory faster; decrease it to return memory
slower. Reasonable rates are in the range [0,10].

|`TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD` |default: 1073741824
|Allocations larger than this value cause a stack trace to be dumped
to stderr. The threshold for dumping stack traces is increased by a
factor of 1.125 every time we print a message so that the threshold
automatically goes up by a factor of ~1000 every 60 messages. This
bounds the amount of extra logging generated by this flag. Default
value of this flag is very large and therefore you should see no extra
logging unless the flag is overridden.

|`TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES` |default: 33554432 |Bound
on the total amount of bytes allocated to thread caches. This bound is
not strict, so it is possible for the cache to go over this bound in
certain circumstances. This value defaults to 16MB. For applications
with many threads, this may not be a large enough cache, which can
affect performance. If you suspect your application is not scaling to
many threads due to lock contention in TCMalloc, you can try
increasing this value. This may improve performance, at a cost of
extra memory use by TCMalloc. See link:#Garbage_Collection[Garbage
Collection] for more details.

|`TCMALLOC_AGGRESSIVE_DECOMMIT` | default: false |Enables "aggressive
decommit mode", which makes all tcmalloc to return all free spans to
kernel. This reduces total phsycical memory usage at cost of some
performance (about 2% cpu hit in Chrome was measured at some point).

|`TCMALLOC_OVERRIDE_PAGESIZE` | default: getpagesize() | Sometimes we
run on systems with larger than anticipatesd hardware page
size. I.e. ARMs (and soon RISC-Vs) can run 64k pages mode. We detect
actual page size at run-time and adjust our span sizings to do memory
management syscalls with correct granularity. Larger pages generally
cause somewhat higher memory fragmentation, so we have this parameter
to be able measuring fragmentation impact of larger pages.

|`TCMALLOC_HEAP_LIMIT_MB` | default: No limit | Sets limit on total
size of page heap (in-use spans and "free but not returned"
spans). When tcmalloc hits this limit it tries to return some free
spans to kernel. And if that isn't enough to keep page heap size under
limit it OOMs. "abseil tcmalloc" has equivalent "hard limit".

|===

Advanced "tweaking" flags, that control more precisely how tcmalloc
tries to allocate memory from the kernel.

[cols=",,",]
|===

|`TCMALLOC_SKIP_MMAP` |default: false |If true, do not try to use
`+mmap+` to obtain memory from the kernel.

|`TCMALLOC_SKIP_SBRK` |default: false |If true, do not try to use
`+sbrk+` to obtain memory from the kernel.

|`TCMALLOC_MEMFS_MALLOC_PATH` |default: "" |If set, specify a path
where hugetlbfs or tmpfs is mounted. This may allow for speedier
allocations.

|`TCMALLOC_MEMFS_LIMIT_MB` |default: 0 |Limit total memfs allocation
size to specified number of MB. 0 means "no limit".

|`TCMALLOC_MEMFS_ABORT_ON_FAIL` |default: false |If true, abort()
whenever memfs_malloc fails to satisfy an allocation.

|`TCMALLOC_MEMFS_IGNORE_MMAP_FAIL` |default: false |If true, ignore
failures from mmap.

|`TCMALLOC_MEMFS_MAP_PRIVATE` |default: false |If true, use
MAP_PRIVATE when mapping via memfs, not MAP_SHARED.

|`TCMALLOC_MEMFS_DISABLE_FALLBACK` |default: false |If true, OOM on
failing to allocate from memfs instead of falling back to anonymous
memory (sbrk/mmap)

|===

== [#compiletime]#Modifying Behavior In Code#

The `+MallocExtension+` class, in `+malloc_extension.h+`, provides a few
knobs that you can tweak in your program, to affect tcmalloc's behavior.

=== Releasing Memory Back to the System

By default, tcmalloc will release no-longer-used memory back to the
kernel gradually, over time. The link:#runtime[tcmalloc_release_rate]
flag controls how quickly this happens. You can also force a release at
a given point in the progam execution like so:

....
   MallocExtension::instance()->ReleaseFreeMemory();
....

You can also call `+SetMemoryReleaseRate()+` to change the
`+tcmalloc_release_rate+` value at runtime, or `+GetMemoryReleaseRate+`
to see what the current release rate is.

=== Memory Introspection

There are several routines for getting a human-readable form of the
current memory usage:

....
   MallocExtension::instance()->GetStats(buffer, buffer_length);
   MallocExtension::instance()->GetHeapSample(&string);
   MallocExtension::instance()->GetHeapGrowthStacks(&string);
....

The last two create files in the same format as the heap-profiler, and
can be passed as data files to pprof. The first is human-readable and is
meant for debugging.

=== Generic Tcmalloc Status

TCMalloc has support for setting and retrieving arbitrary 'properties':

....
   MallocExtension::instance()->SetNumericProperty(property_name, value);
   MallocExtension::instance()->GetNumericProperty(property_name, &value);
....

It is possible for an application to set and get these properties, but
the most useful is when a library sets the properties so the application
can read them. Here are the properties TCMalloc defines; you can access
them with a call like
`MallocExtension::instance()->GetNumericProperty("generic.heap_size", &value);`:

[cols=",",]
|===

|`generic.current_allocated_bytes` |Number of bytes used by the
application. This will not typically match the memory use reported by
the OS, because it does not include TCMalloc overhead or memory
fragmentation.

|`generic.heap_size` |Bytes of system memory reserved by TCMalloc.

|`tcmalloc.pageheap_free_bytes` |Number of bytes in free, mapped pages
in page heap. These bytes can be used to fulfill allocation requests.
They always count towards virtual memory usage, and unless the
underlying memory is swapped out by the OS, they also count towards
physical memory usage.

|`tcmalloc.pageheap_unmapped_bytes` |Number of bytes in free, unmapped
pages in page heap. These are bytes that have been released back to the
OS, possibly by one of the MallocExtension "Release" calls. They can be
used to fulfill allocation requests, but typically incur a page fault.
They always count towards virtual memory usage, and depending on the OS,
typically do not count towards physical memory usage.

|`tcmalloc.slack_bytes` |Sum of pageheap_free_bytes and
pageheap_unmapped_bytes. Provided for backwards compatibility only. Do
not use.

|`tcmalloc.max_total_thread_cache_bytes` |A limit to how much memory
TCMalloc dedicates for small objects. Higher numbers trade off more
memory use for -- in some situations -- improved efficiency.

|`tcmalloc.current_total_thread_cache_bytes` |A measure of some of the
memory TCMalloc is using (for small objects).

|`tcmalloc.min_per_thread_cache_bytes` |A lower limit to how much
memory TCMalloc dedicates for small objects per thread. Note that this
property only shows effect if per-thread cache calculated using
tcmalloc.max_total_thread_cache_bytes ended up being less than
tcmalloc.min_per_thread_cache_bytes.

|===

=== [#caveats]#Caveats#

TCMalloc may be somewhat more memory hungry than other mallocs, (but
tends not to have the huge blowups that can happen with other mallocs).
In particular, at startup TCMalloc allocates approximately 240KB of
internal memory.

Don't try to load TCMalloc into a running binary (e.g., using JNI in
Java programs). The binary will have allocated some objects using the
system malloc, and may try to pass them to TCMalloc for deallocation.
TCMalloc will not be able to handle such objects.

'''''

Original author: Sanjay Ghemawat +
Last updated by: Aliaksei Kandratsenka (Dec 2024)
gperftools-gperftools-2.18/docs/threadheap.gif000066400000000000000000000166231513545575200215620ustar00rootroot00000000000000GIF89aN___???!,NI8ͻ`(dihlp,tmx|pH,Ȥ^I8ͻ`(divP@NZYڋ޼Hf^I8ͻ`(divP@NZYڋ޼Hf^I8ͻ`(divP@NZYڋ޼Hf^I8ͻ`(divP@NZYڋ޼Hf^I8ͻ`(divP@NZYڋ޼Hf^{m+!V{q0I9igy
I8pV(@ '1cavA9ig{
^0c0.(@ 'w{o V{ý[caa^{mrjo{+ V{Ac10ڋaMP@NZ
{orj/c1aa V{q;콷	
I{P@NZc100rj/z6A9i7{
I `1a]P@NZ@&Xk	
I8ˠ59ig0@ '7B9i#kJ$9ig0@ ',^[(@ '4k3
@(RJ%9)ZgB@N
BVj V{q[~ V{	Ir@)R*a9eRJi($(H	2PJ)
I8mPI#G9eRJ)09 @ '{09 @ '19'rj/zϠ %K119A	cBi($(I%I{-rR	rj/c`N^y`(H&B Q0Qrh 'L!V{aV{qI9ig
ڋ!B@ Ca$A"!(
R(J4 V{ýZ9igC0@ a0B	4)9B4PJQEQ V{ýZ V{Ac9igk0 0!LxJ@S@N@‘'Jrj
!` V{C@N(R
rjo
!`1a6A9	h#C@`0B`0B@NpB)Jrj/2ha@NZY3I8ͻP@yB@`! B`
rJR(R V{qAkrj/2ha@NZYOB&$ !V{q
C!BR%8LH#``rNJT^eڋZg V{qӘ	H^\C9,ڋZc V{qArj/z- V{q;콷	
I{P@NZc100rj/z6A9i7{
I `1a]P@NZY&(@ '{キB9i10ð
I8pV(@ '1cavA9ig{
^0c0.(@ 'w{o V{ý[caa^{mrjo{+ V{Ac10ڋaMPV{%rj/9iwB '7B9igrj/z?#Y V{q;@ '78A9igrj/z?#Y V{q;@ '78A9igrj/z?#Y V{q;@ '78A9igrj/z?#Y V{q;@ '78AANZYo	ڋ޼Hf^I8ͻ`(divP@NZYڋ޼Hf^I8ͻ`(divP@NZYڋ޼Hf^I8ͻ`(divP@NZYڋ޼Hf^I8ͻ`(divP@NZYڋ޼Hf^I8ͻ`(divP@NZY&(I9ig	;!V{q֛woڋaMP@NZ
{orj/c1aa V{q;콷	
I{P@NZc100rj/z6A9i7{
I `1a]P@NZY&(@ '{キB9i10ð
I8pV(@ '1cavA9ig{
^0c0.(@ 'w{o V{ý[caaUdZ˚ڋZc V{qArj/z- 9BZ19)ZkUrjo{+ V{Ac108B@N
BJIA:CUUUrRjPkUUڋ:KC3`a@N(R(((	
RB RJ)9i 'rj/z/rj/
π1IPs@@NZ
kas@@NZcrN^AAJ0	 b0br(RJ)EQp99i10I'rj/Z<`0c@((9iN^)rj/rj/9i 'L!V{q8d@d2$@P+ZU '
^0 'I8r9esL0H!
 ZA֪ g@ g@I8]C!!AaSr(RJ)EQ$r@)@)EQEIPIRJA@NZ!10&(@ 4qdF(F(ICt^eڋZg V{q֛woH3B@0V'F'!P:rj/2ha@NZY3I8IȄ$rj/!c`(BH	i$#́@NyRP
rj/2ha@NZY3I8ī$rj/!sMP@NZY1I8ˠu9igy
I8pV(@ '1cavA9ig{
^0c0.(@ 'w{o V{ý[caa^{mrjo{+ V{Ac10ڋaMP@NZ
{orj/c1aa V{q;콷	
I{P@NZc100rj/z6A9i7{
I `1a]P@NZY&(I9ig	;!V{q֛woڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wP '⬷@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w{o^	ڋANZI8ͻP@NZY&(@ '{キB9i10ð
I8pV(@ '1cavA9ig{
^0c0.(@ 'w{o V{ý[caa^{mrjo{+ V{Ac10ڋaMP@NZ
{orj/c1aa V{q;콷	
I{P@NZc100r*2ZkeMP@NZY1I8ˠu9igy
I!Xk ^eڋZg V{q֛wo&)A RJ)Zk3ZUUEA!@ 'Z+
VUUMPI8PI
P@NZ0H	2PJ)4PJQEQ@N(R
rjoAN^_(^c  I8=` ,!@
`
`Si֪ ' @ '{0I%I `1AN:!V{q:@ 
0F0FI
R^)rj/rj/9i 'L!V{q8d@d2$@TRkZQPrjo^4 V{AcTB 'w!F2 4 RjZ9rjo^9rj/c`3@ 'w
0 A2	O	pJ@9Q@)EQ$r@)@)EQEIPIRJA@NZ!10&(@ 4qdF(F()QڋZc V{qArj/z- siA*X(14@ ',^e:ڋLH@B '28B)J pF20<0rڋZc V{qArj/z31	ڋk9e V{qAkrj/2ha@NZYo޽rj/z6A9i7{
I `1a]P@NZY&(@ '{キB9i10ð
I8pV(@ '1cavA9ig{
^0c0.(@ 'w{o V{ý[caa^{mrjo{+ V{Ac10ڋaMP@NZ
{orj/c1aa V{q;콷	
rj@NZY 'N^[(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(I8-!V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPڋ9igyő,
I8 V{q֛wPK$dH V[rj/z?#Y V{L
rjk@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G4;(@ 'w@NZYoCq$Krj/z^0G@4;(I8-!V{q֛wPQ;gperftools-gperftools-2.18/gen_compile_commands.rb000077500000000000000000000052341513545575200225240ustar00rootroot00000000000000#!/usr/bin/ruby

# Use this script to produce compile_commands.json useful to feed
# clangd/ccls. Helpful for modern IDEs.

require 'json'

DIRNAME = File.dirname(__FILE__)
Dir.chdir(DIRNAME)

all_files = Dir['**/*.h'] + Dir['**/*.c'] + Dir['**/*.cc']
all_files.sort!

def classify(path)
  return :skip if path =~ /\/googletest\/.*\/test\//
  return :skip if path == "src/config.h"

  return :skip if path =~ /gmock/
  return :skip if path =~ /\/googletest\/samples\//
  return :skip if path.end_with?("/gtest-all.cc")

  return :skip if path.start_with?("src/windows/")
  return :skip if path.start_with?("vsprojects/")

  if path =~ /libbacktrace(\/|-)/
    return :default if path.end_with?(".cc")
    return :libbacktrace
  end

  :default
end

NORMAL_INCLUDES = %w[
  benchmark/ generic-config/ src/gperftools/
  src/base/ src/
  vendor/googletest/googletest/include/
  vendor/googletest/googletest/
].map {|d| "-I#{d}"}

entries = all_files.map do |filename|
  args = case classify(filename)
         when :default
           # various libc_override_xyz headers
           # (e.g. libc_override_glibc.h) are not standalone, but we
           # can make clangd "compile" them by including
           # src/libc_override.h but setting up this "inclusion" to
           # skip actual override includes. Yes, ugly. But it works,
           # mostly.
           maybe_libc_override = if filename =~ /libc_override_/
                                   %w[-include src/libc_override.h -DTCMALLOC_SKIP_OVERRIDE]
                                 else
                                   []
                                 end
           # Note, getpc.h cannot include "config.h" because it is
           # being used by ./configure script. So we need to "help" it
           # for the clangd case.
           maybe_generic_config = if File.basename(filename) == "getpc.h"
                                    %w[-include generic-config/config.h]
                                  else
                                    []
                                  end
           ["clang++", "-x", "c++", "-std=c++17",
            "-DENABLE_EMERGENCY_MALLOC",
            *NORMAL_INCLUDES,
            *maybe_libc_override,
            *maybe_generic_config,
            "--", filename]
         when :libbacktrace
           ["clang",
            "-Ivendor/libbacktrace-integration",
            "-Ivendor/libbacktrace",
            "--", filename]
         when :skip
           next
         end
  {file: filename,
   directory: Dir.pwd,
   arguments: args}
end.compact

File.open("compile_commands.json", "w") do |f|
  f.puts JSON.pretty_generate(entries)
end
puts "produced #{File.join(DIRNAME, "compile_commands.json")}"
gperftools-gperftools-2.18/generic-config/000077500000000000000000000000001513545575200207055ustar00rootroot00000000000000gperftools-gperftools-2.18/generic-config/config.h000066400000000000000000000205601513545575200223260ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Note, this is somewhat "poor man's" equivalent of config.h that is
// normally produced by autotools. It detects features at compile
// time, so it is easier to integrate with stuff like bazel, but it
// supports fewer platforms. As of this writing it is tested on modern
// GNU/Linux and Windows (MSVC).
#ifndef GPERFTOOLS_CONFIG_H_
#define GPERFTOOLS_CONFIG_H_

/* enable aggressive decommit by default */
/* #undef ENABLE_AGGRESSIVE_DECOMMIT_BY_DEFAULT */

/* Build runtime detection for sized delete */
/* #undef ENABLE_DYNAMIC_SIZED_DELETE */

/* report large allocation */
/* #undef ENABLE_LARGE_ALLOC_REPORT */

/* Build sized deletion operators */
/* #undef ENABLE_SIZED_DELETE */

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_ASM_PTRACE_H 1
#  endif
#endif

/* Whether  contains __cxxabiv1::__cxa_demangle */
#ifdef __GNUC__
#define HAVE_CXA_DEMANGLE 1
#endif

/* Define to 1 if you have the declaration of 'backtrace', and to 0 if you
   don't. */
/* #undef HAVE_DECL_BACKTRACE */

/* Define to 1 if you have the declaration of 'backtrace_symbols', and to 0 if
   you don't. */
// #undef HAVE_DECL_BACKTRACE_SYMBOLS 1

/* Define to 1 if you have the declaration of 'memalign', and to 0 if you
   don't. */
// memalign is legacy API. BSDs have already removed it.
#if __linux__
#define HAVE_DECL_MEMALIGN 1
#endif

/* Define to 1 if you have the declaration of 'nanosleep', and to 0 if you
   don't. */
/* #undef HAVE_DECL_NANOSLEEP */

/* Define to 1 if you have the declaration of 'posix_memalign', and to 0 if
   you don't. */
// We keep it simple for generic config.h and assume anything
// non-windows is modern enough.
#ifndef _WIN32
#define HAVE_DECL_POSIX_MEMALIGN 1
#endif

/* Define to 1 if you have the declaration of 'pvalloc', and to 0 if you
   don't. */
#if __linux__
// same as memalign above.
#define HAVE_DECL_PVALLOC 1
#endif

// Nothing else is using it
#if defined(__MINGW32__)
#define HAVE_DECL_SLEEP 1
#define HAVE_DECL_NANOSLEEP 1
#endif

/* Define to 1 if you have the declaration of 'valloc', and to 0 if you don't.
   */
#if __linux__
// same as memalign above
#define HAVE_DECL_VALLOC 1
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_DLFCN_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_EXECINFO_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_FCNTL_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    include  // for __GLIBC__ define below and elsewhere
#  endif
#endif

/* Define to 1 if you have the 'geteuid' function. */
#ifndef _WIN32
#define HAVE_GETEUID 1
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_GLOB_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_INTTYPES_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_LIBUNWIND_H 1
#  endif
#endif

/* Define if this is Linux that has SIGEV_THREAD_ID */
#if __linux__
#define HAVE_LINUX_SIGEV_THREAD_ID 1
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_MALLOC_H 1
#  endif
#endif

/* Define to 1 if you have a working `mmap' system call. */
#ifndef _WIN32
#define HAVE_MMAP 1
#endif

/* define if libc has program_invocation_name */
#if __linux__
#define HAVE_PROGRAM_INVOCATION_NAME 1
#endif

/* Define to 1 if you have the 'sbrk' function. */
#if __linux__
// Some BSDs already started removing sbrk. So we keep it simple for
// now.
#define HAVE_SBRK 1
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_SCHED_H 1
#  endif
#endif


/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_SYS_CDEFS_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_SYS_STAT_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_SYS_SYSCALL_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_SYS_TYPES_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_SYS_UCONTEXT_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include()
#    define HAVE_UCONTEXT_H 1
#  endif
#endif

/* Define to 1 if you have the  header file. */
#if defined __has_include
#  if __has_include() && !defined(_WIN32)
#    define HAVE_UNISTD_H 1
#  endif
#endif

/* Whether  contains _Unwind_Backtrace */
// Apparently both clang (even with -stdlib=libc++) and gcc have
// Unwind_Backtrace. But we seem to be avoiding it on OSX and FreeBSD,
// reportedly due to recursing back into malloc (see matching comment
// in configure.ac)
#if defined(__GNUC__) && !defined(__APPLE__) && !defined(__FreeBSD__)
#define HAVE_UNWIND_BACKTRACE 1
#endif

#ifdef __GNUC__
/* define if your compiler has __attribute__ */
#define HAVE___ATTRIBUTE__ 1
/* define if your compiler supports alignment of functions */
#define HAVE___ATTRIBUTE__ALIGNED_FN 1
#endif

/* dllexport or attribute visibility */
#ifndef PERFTOOLS_DLL_DECL
#define PERFTOOLS_DLL_DECL /**/
#endif

/* if libgcc stacktrace method should be default */
/* #undef PREFER_LIBGCC_UNWINDER */

/* Define 8 bytes of allocation alignment for tcmalloc */
/* #undef TCMALLOC_ALIGN_8BYTES */

/* Define internal page size for tcmalloc as number of left bitshift */
/* #undef TCMALLOC_PAGE_SIZE_SHIFT */

/* libunwind.h was found and is working */
//#define USE_LIBUNWIND 1

/* C99 says: define this to get the PRI... macros from stdint.h */
#ifndef __STDC_FORMAT_MACROS
# define __STDC_FORMAT_MACROS 1
#endif


#ifdef _WIN32
// TODO(csilvers): include windows/port.h in every relevant source file instead?
#include "windows/port.h"
#endif

#endif  /* #ifndef GPERFTOOLS_CONFIG_H_ */
gperftools-gperftools-2.18/gperftools.sln000066400000000000000000000623111513545575200207330ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtcmalloc_minimal", "vsprojects\libtcmalloc_minimal\libtcmalloc_minimal.vcxproj", "{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcmalloc_minimal_unittest", "vsprojects\tcmalloc_minimal_unittest\tcmalloc_minimal_unittest.vcxproj", "{7CC73D97-C057-43A6-82EF-E6B567488D02}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcmalloc_minimal_large_unittest", "vsprojects\tcmalloc_minimal_large\tcmalloc_minimal_large_unittest.vcxproj", "{2D8B9599-C74C-4298-B723-6CF6077563E3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "addressmap_unittest", "vsprojects\addressmap_unittest\addressmap_unittest.vcxproj", "{32EECEB6-7D18-477E-BC7A-30CE98457A88}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "frag_unittest", "vsprojects\frag_unittest\frag_unittest.vcxproj", "{24754725-DE0D-4214-8979-324247AAD78E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "low_level_alloc_unittest", "vsprojects\low_level_alloc_unittest\low_level_alloc_unittest.vcxproj", "{A765198D-5305-4AB0-9A21-A0CD8201EB2A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "malloc_hook_test", "vsprojects\malloc_hook_test\malloc_hook_test.vcxproj", "{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "malloc_extension_test", "vsprojects\malloc_extension_test\malloc_extension_test.vcxproj", "{3765198D-5305-4AB0-9A21-A0CD8201EB2A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "markidle_unittest", "vsprojects\markidle_unittest\markidle_unittest.vcxproj", "{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "current_allocated_bytes_test", "vsprojects\current_allocated_bytes_test\current_allocated_bytes_test.vcxproj", "{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "packed-cache_test", "vsprojects\packed-cache_test\packed-cache_test.vcxproj", "{605D3CED-B530-424E-B7D2-2A31F14FD570}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pagemap_unittest", "vsprojects\pagemap_unittest\pagemap_unittest.vcxproj", "{9765198D-5305-4AB0-9A21-A0CD8201EB2A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "page_heap_test", "vsprojects\page_heap_test\page_heap_test.vcxproj", "{9765198D-5305-4AB0-9A21-A0CD8201EB2B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "realloc_unittest", "vsprojects\realloc_unittest\realloc_unittest.vcxproj", "{4765198D-5305-4AB0-9A21-A0CD8201EB2A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sampler_test", "vsprojects\sampler_test\sampler_test.vcxproj", "{B765198D-5305-4AB0-9A21-A0CD8201EB2A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stack_trace_table_test", "vsprojects\stack_trace_table_test\stack_trace_table_test.vcxproj", "{A4754725-DE0D-4214-8979-324247AAD78E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thread_dealloc_unittest", "vsprojects\thread_dealloc_unittest\thread_dealloc_unittest.vcxproj", "{6CFFBD0F-09E3-4282-A711-0564451FDF74}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "preamble_patcher_test", "vsprojects\preamble_patcher_test\preamble_patcher_test.vcxproj", "{5765198D-5305-4AB0-9A21-A0CD8201EB2A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "system-alloc_unittest", "vsprojects\system-alloc_unittest\system-alloc_unittest.vcxproj", "{387F753A-0312-4A7B-A1D6-B2795E832E96}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "vsprojects\gtest\gtest.vcxproj", "{0496DF42-D7AD-46B6-B10C-C57A07E89B0D}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release-Override|x64 = Release-Override|x64
		Release-Override|x86 = Release-Override|x86
		Release-Patch|x64 = Release-Patch|x64
		Release-Patch|x86 = Release-Patch|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Debug|x64.ActiveCfg = Debug|x64
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Debug|x64.Build.0 = Debug|x64
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Debug|x86.ActiveCfg = Debug|Win32
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Debug|x86.Build.0 = Debug|Win32
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release-Override|x64.Build.0 = Release-Override|x64
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release-Override|x86.Build.0 = Release-Override|Win32
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Debug|x64.ActiveCfg = Debug|x64
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Debug|x64.Build.0 = Debug|x64
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Debug|x86.ActiveCfg = Debug|Win32
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Debug|x86.Build.0 = Debug|Win32
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Release-Override|x64.Build.0 = Release-Override|x64
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Release-Override|x86.Build.0 = Release-Override|Win32
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{7CC73D97-C057-43A6-82EF-E6B567488D02}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Debug|x64.ActiveCfg = Debug|x64
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Debug|x64.Build.0 = Debug|x64
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Debug|x86.ActiveCfg = Debug|Win32
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Debug|x86.Build.0 = Debug|Win32
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Release-Override|x64.Build.0 = Release-Override|x64
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Release-Override|x86.Build.0 = Release-Override|Win32
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{2D8B9599-C74C-4298-B723-6CF6077563E3}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Debug|x64.ActiveCfg = Debug|x64
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Debug|x64.Build.0 = Debug|x64
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Debug|x86.ActiveCfg = Debug|Win32
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Debug|x86.Build.0 = Debug|Win32
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release-Override|x64.Build.0 = Release-Override|x64
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release-Override|x86.Build.0 = Release-Override|Win32
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{24754725-DE0D-4214-8979-324247AAD78E}.Debug|x64.ActiveCfg = Debug|x64
		{24754725-DE0D-4214-8979-324247AAD78E}.Debug|x64.Build.0 = Debug|x64
		{24754725-DE0D-4214-8979-324247AAD78E}.Debug|x86.ActiveCfg = Debug|Win32
		{24754725-DE0D-4214-8979-324247AAD78E}.Debug|x86.Build.0 = Debug|Win32
		{24754725-DE0D-4214-8979-324247AAD78E}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{24754725-DE0D-4214-8979-324247AAD78E}.Release-Override|x64.Build.0 = Release-Override|x64
		{24754725-DE0D-4214-8979-324247AAD78E}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{24754725-DE0D-4214-8979-324247AAD78E}.Release-Override|x86.Build.0 = Release-Override|Win32
		{24754725-DE0D-4214-8979-324247AAD78E}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{24754725-DE0D-4214-8979-324247AAD78E}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{24754725-DE0D-4214-8979-324247AAD78E}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{24754725-DE0D-4214-8979-324247AAD78E}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.ActiveCfg = Debug|x64
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.Build.0 = Debug|x64
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.ActiveCfg = Debug|Win32
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.Build.0 = Debug|Win32
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.Build.0 = Release-Override|x64
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.Build.0 = Release-Override|Win32
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Debug|x64.ActiveCfg = Debug|x64
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Debug|x64.Build.0 = Debug|x64
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Debug|x86.ActiveCfg = Debug|Win32
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Debug|x86.Build.0 = Debug|Win32
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.Build.0 = Release-Override|x64
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.Build.0 = Release-Override|Win32
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.ActiveCfg = Debug|x64
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.Build.0 = Debug|x64
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.ActiveCfg = Debug|Win32
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.Build.0 = Debug|Win32
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.Build.0 = Release-Override|x64
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.Build.0 = Release-Override|Win32
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug|x64.ActiveCfg = Debug|x64
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug|x64.Build.0 = Debug|x64
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug|x86.ActiveCfg = Debug|Win32
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug|x86.Build.0 = Debug|Win32
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Override|x64.Build.0 = Release-Override|x64
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Override|x86.Build.0 = Release-Override|Win32
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug|x64.ActiveCfg = Debug|x64
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug|x64.Build.0 = Debug|x64
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug|x86.ActiveCfg = Debug|Win32
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug|x86.Build.0 = Debug|Win32
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Override|x64.Build.0 = Release-Override|x64
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Override|x86.Build.0 = Release-Override|Win32
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug|x64.ActiveCfg = Debug|x64
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug|x64.Build.0 = Debug|x64
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug|x86.ActiveCfg = Debug|Win32
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug|x86.Build.0 = Debug|Win32
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release-Override|x64.Build.0 = Release-Override|x64
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release-Override|x86.Build.0 = Release-Override|Win32
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.ActiveCfg = Debug|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.Build.0 = Debug|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.ActiveCfg = Debug|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.Build.0 = Debug|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.Build.0 = Release-Override|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.Build.0 = Release-Override|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Debug|x64.ActiveCfg = Debug|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Debug|x64.Build.0 = Debug|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Debug|x86.ActiveCfg = Debug|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Debug|x86.Build.0 = Debug|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release-Override|x64.Build.0 = Release-Override|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release-Override|x86.Build.0 = Release-Override|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.ActiveCfg = Debug|x64
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.Build.0 = Debug|x64
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.ActiveCfg = Debug|Win32
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.Build.0 = Debug|Win32
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.Build.0 = Release-Override|x64
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.Build.0 = Release-Override|Win32
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.ActiveCfg = Debug|x64
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.Build.0 = Debug|x64
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.ActiveCfg = Debug|Win32
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.Build.0 = Debug|Win32
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.Build.0 = Release-Override|x64
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.Build.0 = Release-Override|Win32
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{A4754725-DE0D-4214-8979-324247AAD78E}.Debug|x64.ActiveCfg = Debug|x64
		{A4754725-DE0D-4214-8979-324247AAD78E}.Debug|x64.Build.0 = Debug|x64
		{A4754725-DE0D-4214-8979-324247AAD78E}.Debug|x86.ActiveCfg = Debug|Win32
		{A4754725-DE0D-4214-8979-324247AAD78E}.Debug|x86.Build.0 = Debug|Win32
		{A4754725-DE0D-4214-8979-324247AAD78E}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{A4754725-DE0D-4214-8979-324247AAD78E}.Release-Override|x64.Build.0 = Release-Override|x64
		{A4754725-DE0D-4214-8979-324247AAD78E}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{A4754725-DE0D-4214-8979-324247AAD78E}.Release-Override|x86.Build.0 = Release-Override|Win32
		{A4754725-DE0D-4214-8979-324247AAD78E}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{A4754725-DE0D-4214-8979-324247AAD78E}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{A4754725-DE0D-4214-8979-324247AAD78E}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{A4754725-DE0D-4214-8979-324247AAD78E}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Debug|x64.ActiveCfg = Debug|x64
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Debug|x64.Build.0 = Debug|x64
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Debug|x86.ActiveCfg = Debug|Win32
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Debug|x86.Build.0 = Debug|Win32
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release-Override|x64.Build.0 = Release-Override|x64
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release-Override|x86.Build.0 = Release-Override|Win32
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{5765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x64.ActiveCfg = Debug|x64
		{5765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug|x86.ActiveCfg = Debug|Win32
		{5765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{5765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{5765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{5765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Debug|x64.ActiveCfg = Debug|x64
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Debug|x64.Build.0 = Debug|x64
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Debug|x86.ActiveCfg = Debug|Win32
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Debug|x86.Build.0 = Debug|Win32
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release-Override|x64.Build.0 = Release-Override|x64
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release-Override|x86.Build.0 = Release-Override|Win32
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Debug|x64.ActiveCfg = Debug|x64
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Debug|x64.Build.0 = Debug|x64
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Debug|x86.ActiveCfg = Debug|Win32
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Debug|x86.Build.0 = Debug|Win32
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release-Override|x64.Build.0 = Release-Override|x64
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release-Override|x86.Build.0 = Release-Override|Win32
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release-Patch|x86.Build.0 = Release-Patch|Win32
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Debug|x64.ActiveCfg = Debug|x64
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Debug|x64.Build.0 = Debug|x64
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Debug|x86.ActiveCfg = Debug|Win32
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Debug|x86.Build.0 = Debug|Win32
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Release-Override|x64.ActiveCfg = Release-Override|x64
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Release-Override|x64.Build.0 = Release-Override|x64
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Release-Override|x86.ActiveCfg = Release-Override|Win32
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Release-Override|x86.Build.0 = Release-Override|Win32
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Release-Patch|x64.ActiveCfg = Release-Patch|x64
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Release-Patch|x64.Build.0 = Release-Patch|x64
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Release-Patch|x86.ActiveCfg = Release-Patch|Win32
		{387F753A-0312-4A7B-A1D6-B2795E832E96}.Release-Patch|x86.Build.0 = Release-Patch|Win32
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
EndGlobal
gperftools-gperftools-2.18/m4/000077500000000000000000000000001513545575200163465ustar00rootroot00000000000000gperftools-gperftools-2.18/m4/ac_have_attribute.m4000066400000000000000000000007671513545575200222730ustar00rootroot00000000000000AC_DEFUN([AX_C___ATTRIBUTE__], [
  AC_MSG_CHECKING(for __attribute__)
  AC_CACHE_VAL(ac_cv___attribute__, [
    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include 
       static void foo(void) __attribute__ ((unused));
       void foo(void) { exit(1); }]], [[]])],[ac_cv___attribute__=yes],[ac_cv___attribute__=no
    ])])
  if test "$ac_cv___attribute__" = "yes"; then
    AC_DEFINE(HAVE___ATTRIBUTE__, 1, [define if your compiler has __attribute__])
  fi
  AC_MSG_RESULT($ac_cv___attribute__)
])
gperftools-gperftools-2.18/m4/acx_nanosleep.m4000066400000000000000000000022021513545575200214230ustar00rootroot00000000000000# Check for support for nanosleep.  It's defined in , but on
# some systems, such as solaris, you need to link in a library to use it.
# We set acx_nanosleep_ok if nanosleep is supported; in that case,
# NANOSLEEP_LIBS is set to whatever libraries are needed to support
# nanosleep.

AC_DEFUN([ACX_NANOSLEEP],
[AC_MSG_CHECKING(if nanosleep requires any libraries)
 AC_LANG_SAVE
 AC_LANG([C])
 acx_nanosleep_ok="no"
 NANOSLEEP_LIBS=
 # For most folks, this should just work
 AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[static struct timespec ts; nanosleep(&ts, NULL);]])],[acx_nanosleep_ok=yes],[])
 # For solaris, we may  need -lrt
 if test "x$acx_nanosleep_ok" != "xyes"; then
   OLD_LIBS="$LIBS"
   LIBS="-lrt $LIBS"
   AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[static struct timespec ts; nanosleep(&ts, NULL);]])],[acx_nanosleep_ok=yes],[])
   if test "x$acx_nanosleep_ok" = "xyes"; then
     NANOSLEEP_LIBS="-lrt"
   fi
   LIBS="$OLD_LIBS"
 fi
 if test "x$acx_nanosleep_ok" != "xyes"; then
   AC_MSG_ERROR([cannot find the nanosleep function])
 else
   AC_MSG_RESULT(${NANOSLEEP_LIBS:-no})
 fi
 AC_LANG_RESTORE
])
gperftools-gperftools-2.18/m4/ax_cxx_compile_stdcxx.m4000066400000000000000000000454561513545575200232250ustar00rootroot00000000000000# ===========================================================================
#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
#   Check for baseline language coverage in the compiler for the specified
#   version of the C++ standard.  If necessary, add switches to CXX and
#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)
#   or '14' (for the C++14 standard).
#
#   The second argument, if specified, indicates whether you insist on an
#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
#   -std=c++11).  If neither is specified, you get whatever works, with
#   preference for an extended mode.
#
#   The third argument, if specified 'mandatory' or if left unspecified,
#   indicates that baseline support for the specified C++ standard is
#   required and that the macro should error out if no mode with that
#   support is found.  If specified 'optional', then configuration proceeds
#   regardless, after defining HAVE_CXX${VERSION} if and only if a
#   supporting mode is found.
#
# LICENSE
#
#   Copyright (c) 2008 Benjamin Kosnik 
#   Copyright (c) 2012 Zack Weinberg 
#   Copyright (c) 2013 Roy Stogner 
#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov 
#   Copyright (c) 2015 Paul Norman 
#   Copyright (c) 2015 Moritz Klammler 
#   Copyright (c) 2016, 2018 Krzesimir Nowak 
#
#   Copying and distribution of this file, with or without modification, are
#   permitted in any medium without royalty provided the copyright notice
#   and this notice are preserved.  This file is offered as-is, without any
#   warranty.

#serial 10

dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl  (serial version number 13).

AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
  m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
        [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
        [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
  m4_if([$2], [], [],
        [$2], [ext], [],
        [$2], [noext], [],
        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
  AC_LANG_PUSH([C++])dnl
  ac_success=no

  m4_if([$2], [noext], [], [dnl
  if test x$ac_success = xno; then
    for alternative in ${ax_cxx_compile_alternatives}; do
      switch="-std=gnu++${alternative}"
      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
                     $cachevar,
        [ac_save_CXX="$CXX"
         CXX="$CXX $switch"
         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
          [eval $cachevar=yes],
          [eval $cachevar=no])
         CXX="$ac_save_CXX"])
      if eval test x\$$cachevar = xyes; then
        CXX="$CXX $switch"
        if test -n "$CXXCPP" ; then
          CXXCPP="$CXXCPP $switch"
        fi
        ac_success=yes
        break
      fi
    done
  fi])

  m4_if([$2], [ext], [], [dnl
  if test x$ac_success = xno; then
    dnl HP's aCC needs +std=c++11 according to:
    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
    dnl Cray's crayCC needs "-h std=c++11"
    for alternative in ${ax_cxx_compile_alternatives}; do
      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
        cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
        AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
                       $cachevar,
          [ac_save_CXX="$CXX"
           CXX="$CXX $switch"
           AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
            [eval $cachevar=yes],
            [eval $cachevar=no])
           CXX="$ac_save_CXX"])
        if eval test x\$$cachevar = xyes; then
          CXX="$CXX $switch"
          if test -n "$CXXCPP" ; then
            CXXCPP="$CXXCPP $switch"
          fi
          ac_success=yes
          break
        fi
      done
      if test x$ac_success = xyes; then
        break
      fi
    done
  fi])
  AC_LANG_POP([C++])
  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
    if test x$ac_success = xno; then
      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
    fi
  fi
  if test x$ac_success = xno; then
    HAVE_CXX$1=0
    AC_MSG_NOTICE([No compiler with C++$1 support was found])
  else
    HAVE_CXX$1=1
    AC_DEFINE(HAVE_CXX$1,1,
              [define if the compiler supports basic C++$1 syntax])
  fi
  AC_SUBST(HAVE_CXX$1)
])


dnl  Test body for checking C++11 support

m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)


dnl  Test body for checking C++14 support

m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)

m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)

dnl  Tests for new features in C++11

m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[

// If the compiler admits that it is not ready for C++11, why torture it?
// Hopefully, this will speed up the test.

#ifndef __cplusplus

#error "This is not a C++ compiler"

#elif __cplusplus < 201103L

#error "This is not a C++11 compiler"

#else

namespace cxx11
{

  namespace test_static_assert
  {

    template 
    struct check
    {
      static_assert(sizeof(int) <= sizeof(T), "not big enough");
    };

  }

  namespace test_final_override
  {

    struct Base
    {
      virtual void f() {}
    };

    struct Derived : public Base
    {
      virtual void f() override {}
    };

  }

  namespace test_double_right_angle_brackets
  {

    template < typename T >
    struct check {};

    typedef check single_type;
    typedef check> double_type;
    typedef check>> triple_type;
    typedef check>>> quadruple_type;

  }

  namespace test_decltype
  {

    int
    f()
    {
      int a = 1;
      decltype(a) b = 2;
      return a + b;
    }

  }

  namespace test_type_deduction
  {

    template < typename T1, typename T2 >
    struct is_same
    {
      static const bool value = false;
    };

    template < typename T >
    struct is_same
    {
      static const bool value = true;
    };

    template < typename T1, typename T2 >
    auto
    add(T1 a1, T2 a2) -> decltype(a1 + a2)
    {
      return a1 + a2;
    }

    int
    test(const int c, volatile int v)
    {
      static_assert(is_same::value == true, "");
      static_assert(is_same::value == false, "");
      static_assert(is_same::value == false, "");
      auto ac = c;
      auto av = v;
      auto sumi = ac + av + 'x';
      auto sumf = ac + av + 1.0;
      static_assert(is_same::value == true, "");
      static_assert(is_same::value == true, "");
      static_assert(is_same::value == true, "");
      static_assert(is_same::value == false, "");
      static_assert(is_same::value == true, "");
      return (sumf > 0.0) ? sumi : add(c, v);
    }

  }

  namespace test_noexcept
  {

    int f() { return 0; }
    int g() noexcept { return 0; }

    static_assert(noexcept(f()) == false, "");
    static_assert(noexcept(g()) == true, "");

  }

  namespace test_constexpr
  {

    template < typename CharT >
    unsigned long constexpr
    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
    {
      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
    }

    template < typename CharT >
    unsigned long constexpr
    strlen_c(const CharT *const s) noexcept
    {
      return strlen_c_r(s, 0UL);
    }

    static_assert(strlen_c("") == 0UL, "");
    static_assert(strlen_c("1") == 1UL, "");
    static_assert(strlen_c("example") == 7UL, "");
    static_assert(strlen_c("another\0example") == 7UL, "");

  }

  namespace test_rvalue_references
  {

    template < int N >
    struct answer
    {
      static constexpr int value = N;
    };

    answer<1> f(int&)       { return answer<1>(); }
    answer<2> f(const int&) { return answer<2>(); }
    answer<3> f(int&&)      { return answer<3>(); }

    void
    test()
    {
      int i = 0;
      const int c = 0;
      static_assert(decltype(f(i))::value == 1, "");
      static_assert(decltype(f(c))::value == 2, "");
      static_assert(decltype(f(0))::value == 3, "");
    }

  }

  namespace test_uniform_initialization
  {

    struct test
    {
      static const int zero {};
      static const int one {1};
    };

    static_assert(test::zero == 0, "");
    static_assert(test::one == 1, "");

  }

  namespace test_lambdas
  {

    void
    test1()
    {
      auto lambda1 = [](){};
      auto lambda2 = lambda1;
      lambda1();
      lambda2();
    }

    int
    test2()
    {
      auto a = [](int i, int j){ return i + j; }(1, 2);
      auto b = []() -> int { return '0'; }();
      auto c = [=](){ return a + b; }();
      auto d = [&](){ return c; }();
      auto e = [a, &b](int x) mutable {
        const auto identity = [](int y){ return y; };
        for (auto i = 0; i < a; ++i)
          a += b--;
        return x + identity(a + b);
      }(0);
      return a + b + c + d + e;
    }

    int
    test3()
    {
      const auto nullary = [](){ return 0; };
      const auto unary = [](int x){ return x; };
      using nullary_t = decltype(nullary);
      using unary_t = decltype(unary);
      const auto higher1st = [](nullary_t f){ return f(); };
      const auto higher2nd = [unary](nullary_t f1){
        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
      };
      return higher1st(nullary) + higher2nd(nullary)(unary);
    }

  }

  namespace test_variadic_templates
  {

    template 
    struct sum;

    template 
    struct sum
    {
      static constexpr auto value = N0 + sum::value;
    };

    template <>
    struct sum<>
    {
      static constexpr auto value = 0;
    };

    static_assert(sum<>::value == 0, "");
    static_assert(sum<1>::value == 1, "");
    static_assert(sum<23>::value == 23, "");
    static_assert(sum<1, 2>::value == 3, "");
    static_assert(sum<5, 5, 11>::value == 21, "");
    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");

  }

  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
  // because of this.
  namespace test_template_alias_sfinae
  {

    struct foo {};

    template
    using member = typename T::member_type;

    template
    void func(...) {}

    template
    void func(member*) {}

    void test();

    void test() { func(0); }

  }

}  // namespace cxx11

#endif  // __cplusplus >= 201103L

]])


dnl  Tests for new features in C++14

m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[

// If the compiler admits that it is not ready for C++14, why torture it?
// Hopefully, this will speed up the test.

#ifndef __cplusplus

#error "This is not a C++ compiler"

#elif __cplusplus < 201402L

#error "This is not a C++14 compiler"

#else

namespace cxx14
{

  namespace test_polymorphic_lambdas
  {

    int
    test()
    {
      const auto lambda = [](auto&&... args){
        const auto istiny = [](auto x){
          return (sizeof(x) == 1UL) ? 1 : 0;
        };
        const int aretiny[] = { istiny(args)... };
        return aretiny[0];
      };
      return lambda(1, 1L, 1.0f, '1');
    }

  }

  namespace test_binary_literals
  {

    constexpr auto ivii = 0b0000000000101010;
    static_assert(ivii == 42, "wrong value");

  }

  namespace test_generalized_constexpr
  {

    template < typename CharT >
    constexpr unsigned long
    strlen_c(const CharT *const s) noexcept
    {
      auto length = 0UL;
      for (auto p = s; *p; ++p)
        ++length;
      return length;
    }

    static_assert(strlen_c("") == 0UL, "");
    static_assert(strlen_c("x") == 1UL, "");
    static_assert(strlen_c("test") == 4UL, "");
    static_assert(strlen_c("another\0test") == 7UL, "");

  }

  namespace test_lambda_init_capture
  {

    int
    test()
    {
      auto x = 0;
      const auto lambda1 = [a = x](int b){ return a + b; };
      const auto lambda2 = [a = lambda1(x)](){ return a; };
      return lambda2();
    }

  }

  namespace test_digit_separators
  {

    constexpr auto ten_million = 100'000'000;
    static_assert(ten_million == 100000000, "");

  }

  namespace test_return_type_deduction
  {

    auto f(int& x) { return x; }
    decltype(auto) g(int& x) { return x; }

    template < typename T1, typename T2 >
    struct is_same
    {
      static constexpr auto value = false;
    };

    template < typename T >
    struct is_same
    {
      static constexpr auto value = true;
    };

    int
    test()
    {
      auto x = 0;
      static_assert(is_same::value, "");
      static_assert(is_same::value, "");
      return x;
    }

  }

}  // namespace cxx14

#endif  // __cplusplus >= 201402L

]])


dnl  Tests for new features in C++17

m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[

// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.

#ifndef __cplusplus

#error "This is not a C++ compiler"

#elif __cplusplus < 201703L

#error "This is not a C++17 compiler"

#else

#include 
#include 
#include 

namespace cxx17
{

  namespace test_constexpr_lambdas
  {

    constexpr int foo = [](){return 42;}();

  }

  namespace test::nested_namespace::definitions
  {

  }

  namespace test_fold_expression
  {

    template
    int multiply(Args... args)
    {
      return (args * ... * 1);
    }

    template
    bool all(Args... args)
    {
      return (args && ...);
    }

  }

  namespace test_extended_static_assert
  {

    static_assert (true);

  }

  namespace test_auto_brace_init_list
  {

    auto foo = {5};
    auto bar {5};

    static_assert(std::is_same, decltype(foo)>::value);
    static_assert(std::is_same::value);
  }

  namespace test_typename_in_template_template_parameter
  {

    template typename X> struct D;

  }

  namespace test_fallthrough_nodiscard_maybe_unused_attributes
  {

    int f1()
    {
      return 42;
    }

    [[nodiscard]] int f2()
    {
      [[maybe_unused]] auto unused = f1();

      switch (f1())
      {
      case 17:
        f1();
        [[fallthrough]];
      case 42:
        f1();
      }
      return f1();
    }

  }

  namespace test_extended_aggregate_initialization
  {

    struct base1
    {
      int b1, b2 = 42;
    };

    struct base2
    {
      base2() {
        b3 = 42;
      }
      int b3;
    };

    struct derived : base1, base2
    {
        int d;
    };

    derived d1 {{1, 2}, {}, 4};  // full initialization
    derived d2 {{}, {}, 4};      // value-initialized bases

  }

  namespace test_general_range_based_for_loop
  {

    struct iter
    {
      int i;

      int& operator* ()
      {
        return i;
      }

      const int& operator* () const
      {
        return i;
      }

      iter& operator++()
      {
        ++i;
        return *this;
      }
    };

    struct sentinel
    {
      int i;
    };

    bool operator== (const iter& i, const sentinel& s)
    {
      return i.i == s.i;
    }

    bool operator!= (const iter& i, const sentinel& s)
    {
      return !(i == s);
    }

    struct range
    {
      iter begin() const
      {
        return {0};
      }

      sentinel end() const
      {
        return {5};
      }
    };

    void f()
    {
      range r {};

      for (auto i : r)
      {
        [[maybe_unused]] auto v = i;
      }
    }

  }

  namespace test_lambda_capture_asterisk_this_by_value
  {

    struct t
    {
      int i;
      int foo()
      {
        return [*this]()
        {
          return i;
        }();
      }
    };

  }

  namespace test_enum_class_construction
  {

    enum class byte : unsigned char
    {};

    byte foo {42};

  }

  namespace test_constexpr_if
  {

    template 
    int f ()
    {
      if constexpr(cond)
      {
        return 13;
      }
      else
      {
        return 42;
      }
    }

  }

  namespace test_selection_statement_with_initializer
  {

    int f()
    {
      return 13;
    }

    int f2()
    {
      if (auto i = f(); i > 0)
      {
        return 3;
      }

      switch (auto i = f(); i + 4)
      {
      case 17:
        return 2;

      default:
        return 1;
      }
    }

  }

  namespace test_template_argument_deduction_for_class_templates
  {

    template 
    struct pair
    {
      pair (T1 p1, T2 p2)
        : m1 {p1},
          m2 {p2}
      {}

      T1 m1;
      T2 m2;
    };

    void f()
    {
      [[maybe_unused]] auto p = pair{13, 42u};
    }

  }

  namespace test_non_type_auto_template_parameters
  {

    template 
    struct B
    {};

    B<5> b1;
    B<'a'> b2;

  }

  namespace test_structured_bindings
  {

    int arr[2] = { 1, 2 };
    std::pair pr = { 1, 2 };

    auto f1() -> int(&)[2]
    {
      return arr;
    }

    auto f2() -> std::pair&
    {
      return pr;
    }

    struct S
    {
      int x1 : 2;
      volatile double y1;
    };

    S f3()
    {
      return {};
    }

    auto [ x1, y1 ] = f1();
    auto& [ xr1, yr1 ] = f1();
    auto [ x2, y2 ] = f2();
    auto& [ xr2, yr2 ] = f2();
    const auto [ x3, y3 ] = f3();

  }

  namespace test_exception_spec_type_system
  {

    struct Good {};
    struct Bad {};

    void g1() noexcept;
    void g2();

    template
    Bad
    f(T*, T*);

    template
    Good
    f(T1*, T2*);

    static_assert (std::is_same_v);

  }

  namespace test_inline_variables
  {

    template void f(T)
    {}

    template inline T g(T)
    {
      return T{};
    }

    template<> inline void f<>(int)
    {}

    template<> int g<>(int)
    {
      return 5;
    }

  }

}  // namespace cxx17

#endif  // __cplusplus < 201703L

]])
gperftools-gperftools-2.18/m4/ax_pthread.m4000066400000000000000000000540341513545575200207350ustar00rootroot00000000000000# ===========================================================================
#        https://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
#   This macro figures out how to build C programs using POSIX threads. It
#   sets the PTHREAD_LIBS output variable to the threads library and linker
#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
#   flags that are needed. (The user can also force certain compiler
#   flags/libs to be tested by setting these environment variables.)
#
#   Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
#   needed for multi-threaded programs (defaults to the value of CC
#   respectively CXX otherwise). (This is necessary on e.g. AIX to use the
#   special cc_r/CC_r compiler alias.)
#
#   NOTE: You are assumed to not only compile your program with these flags,
#   but also to link with them as well. For example, you might link with
#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#   $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
#   If you are only building threaded programs, you may wish to use these
#   variables in your default LIBS, CFLAGS, and CC:
#
#     LIBS="$PTHREAD_LIBS $LIBS"
#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
#     CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
#     CC="$PTHREAD_CC"
#     CXX="$PTHREAD_CXX"
#
#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
#   has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
#   that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
#   PTHREAD_CFLAGS.
#
#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
#   is not found. If ACTION-IF-FOUND is not specified, the default action
#   will define HAVE_PTHREAD.
#
#   Please let the authors know if this macro fails on any platform, or if
#   you have any other suggestions or comments. This macro was based on work
#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
#   grateful for the helpful feedback of numerous users.
#
#   Updated for Autoconf 2.68 by Daniel Richard G.
#
# LICENSE
#
#   Copyright (c) 2008 Steven G. Johnson 
#   Copyright (c) 2011 Daniel Richard G. 
#   Copyright (c) 2019 Marc Stevens 
#
#   This program is free software: you can redistribute it and/or modify it
#   under the terms of the GNU General Public License as published by the
#   Free Software Foundation, either version 3 of the License, or (at your
#   option) any later version.
#
#   This program is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
#   Public License for more details.
#
#   You should have received a copy of the GNU General Public License along
#   with this program. If not, see .
#
#   As a special exception, the respective Autoconf Macro's copyright owner
#   gives unlimited permission to copy, distribute and modify the configure
#   scripts that are the output of Autoconf when processing the Macro. You
#   need not follow the terms of the GNU General Public License when using
#   or distributing such scripts, even though portions of the text of the
#   Macro appear in them. The GNU General Public License (GPL) does govern
#   all other use of the material that constitutes the Autoconf Macro.
#
#   This special exception to the GPL applies to versions of the Autoconf
#   Macro released by the Autoconf Archive. When you make and distribute a
#   modified version of the Autoconf Macro, you may extend this special
#   exception to the GPL to apply to your modified version as well.

#serial 31

AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_PROG_SED])
AC_LANG_PUSH([C])
ax_pthread_ok=no

# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on Tru64 or Sequent).
# It gets checked for in the link test anyway.

# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
        ax_pthread_save_CC="$CC"
        ax_pthread_save_CFLAGS="$CFLAGS"
        ax_pthread_save_LIBS="$LIBS"
        AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
        AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
        LIBS="$PTHREAD_LIBS $LIBS"
        AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
        AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
        AC_MSG_RESULT([$ax_pthread_ok])
        if test "x$ax_pthread_ok" = "xno"; then
                PTHREAD_LIBS=""
                PTHREAD_CFLAGS=""
        fi
        CC="$ax_pthread_save_CC"
        CFLAGS="$ax_pthread_save_CFLAGS"
        LIBS="$ax_pthread_save_LIBS"
fi

# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).

# Create a list of thread flags to try. Items with a "," contain both
# C compiler flags (before ",") and linker flags (after ","). Other items
# starting with a "-" are C compiler flags, and remaining items are
# library names, except for "none" which indicates that we try without
# any flags at all, and "pthread-config" which is a program returning
# the flags for the Pth emulation library.

ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"

# The ordering *is* (sometimes) important.  Some notes on the
# individual items follow:

# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
#       other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
#           (Note: HP C rejects this with "bad form for `-t' option")
# -pthreads: Solaris/gcc (Note: HP C also rejects)
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
#      doesn't hurt to check since this sometimes defines pthreads and
#      -D_REENTRANT too), HP C (must be checked before -lpthread, which
#      is present but should not be used directly; and before -mthreads,
#      because the compiler interprets this as "-mt" + "-hreads")
# -mthreads: Mingw32/gcc, Lynx/gcc
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)

case $host_os in

        freebsd*)

        # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
        # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)

        ax_pthread_flags="-kthread lthread $ax_pthread_flags"
        ;;

        hpux*)

        # From the cc(1) man page: "[-mt] Sets various -D flags to enable
        # multi-threading and also sets -lpthread."

        ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
        ;;

        openedition*)

        # IBM z/OS requires a feature-test macro to be defined in order to
        # enable POSIX threads at all, so give the user a hint if this is
        # not set. (We don't define these ourselves, as they can affect
        # other portions of the system API in unpredictable ways.)

        AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
            [
#            if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
             AX_PTHREAD_ZOS_MISSING
#            endif
            ],
            [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
        ;;

        solaris*)

        # On Solaris (at least, for some versions), libc contains stubbed
        # (non-functional) versions of the pthreads routines, so link-based
        # tests will erroneously succeed. (N.B.: The stubs are missing
        # pthread_cleanup_push, or rather a function called by this macro,
        # so we could check for that, but who knows whether they'll stub
        # that too in a future libc.)  So we'll check first for the
        # standard Solaris way of linking pthreads (-mt -lpthread).

        ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
        ;;
esac

# Are we compiling with Clang?

AC_CACHE_CHECK([whether $CC is Clang],
    [ax_cv_PTHREAD_CLANG],
    [ax_cv_PTHREAD_CLANG=no
     # Note that Autoconf sets GCC=yes for Clang as well as GCC
     if test "x$GCC" = "xyes"; then
        AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
            [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
#            if defined(__clang__) && defined(__llvm__)
             AX_PTHREAD_CC_IS_CLANG
#            endif
            ],
            [ax_cv_PTHREAD_CLANG=yes])
     fi
    ])
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"


# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)

# Note that for GCC and Clang -pthread generally implies -lpthread,
# except when -nostdlib is passed.
# This is problematic using libtool to build C++ shared libraries with pthread:
# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
# To solve this, first try -pthread together with -lpthread for GCC

AS_IF([test "x$GCC" = "xyes"],
      [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])

# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first

AS_IF([test "x$ax_pthread_clang" = "xyes"],
      [ax_pthread_flags="-pthread,-lpthread -pthread"])


# The presence of a feature test macro requesting re-entrant function
# definitions is, on some systems, a strong hint that pthreads support is
# correctly enabled

case $host_os in
        darwin* | hpux* | linux* | osf* | solaris*)
        ax_pthread_check_macro="_REENTRANT"
        ;;

        aix*)
        ax_pthread_check_macro="_THREAD_SAFE"
        ;;

        *)
        ax_pthread_check_macro="--"
        ;;
esac
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
      [ax_pthread_check_cond=0],
      [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])


if test "x$ax_pthread_ok" = "xno"; then
for ax_pthread_try_flag in $ax_pthread_flags; do

        case $ax_pthread_try_flag in
                none)
                AC_MSG_CHECKING([whether pthreads work without any flags])
                ;;

                *,*)
                PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
                PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
                AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
                ;;

                -*)
                AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
                PTHREAD_CFLAGS="$ax_pthread_try_flag"
                ;;

                pthread-config)
                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
                AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
                PTHREAD_CFLAGS="`pthread-config --cflags`"
                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
                ;;

                *)
                AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
                PTHREAD_LIBS="-l$ax_pthread_try_flag"
                ;;
        esac

        ax_pthread_save_CFLAGS="$CFLAGS"
        ax_pthread_save_LIBS="$LIBS"
        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
        LIBS="$PTHREAD_LIBS $LIBS"

        # Check for various functions.  We must include pthread.h,
        # since some functions may be macros.  (On the Sequent, we
        # need a special flag -Kthread to make this header compile.)
        # We check for pthread_join because it is in -lpthread on IRIX
        # while pthread_create is in libc.  We check for pthread_attr_init
        # due to DEC craziness with -lpthreads.  We check for
        # pthread_cleanup_push because it is one of the few pthread
        # functions on Solaris that doesn't have a non-functional libc stub.
        # We try pthread_create on general principles.

        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include 
#                       if $ax_pthread_check_cond
#                        error "$ax_pthread_check_macro must be defined"
#                       endif
                        static void *some_global = NULL;
                        static void routine(void *a)
                          {
                             /* To avoid any unused-parameter or
                                unused-but-set-parameter warning.  */
                             some_global = a;
                          }
                        static void *start_routine(void *a) { return a; }],
                       [pthread_t th; pthread_attr_t attr;
                        pthread_create(&th, 0, start_routine, 0);
                        pthread_join(th, 0);
                        pthread_attr_init(&attr);
                        pthread_cleanup_push(routine, 0);
                        pthread_cleanup_pop(0) /* ; */])],
            [ax_pthread_ok=yes],
            [])

        CFLAGS="$ax_pthread_save_CFLAGS"
        LIBS="$ax_pthread_save_LIBS"

        AC_MSG_RESULT([$ax_pthread_ok])
        AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])

        PTHREAD_LIBS=""
        PTHREAD_CFLAGS=""
done
fi


# Clang needs special handling, because older versions handle the -pthread
# option in a rather... idiosyncratic way

if test "x$ax_pthread_clang" = "xyes"; then

        # Clang takes -pthread; it has never supported any other flag

        # (Note 1: This will need to be revisited if a system that Clang
        # supports has POSIX threads in a separate library.  This tends not
        # to be the way of modern systems, but it's conceivable.)

        # (Note 2: On some systems, notably Darwin, -pthread is not needed
        # to get POSIX threads support; the API is always present and
        # active.  We could reasonably leave PTHREAD_CFLAGS empty.  But
        # -pthread does define _REENTRANT, and while the Darwin headers
        # ignore this macro, third-party headers might not.)

        # However, older versions of Clang make a point of warning the user
        # that, in an invocation where only linking and no compilation is
        # taking place, the -pthread option has no effect ("argument unused
        # during compilation").  They expect -pthread to be passed in only
        # when source code is being compiled.
        #
        # Problem is, this is at odds with the way Automake and most other
        # C build frameworks function, which is that the same flags used in
        # compilation (CFLAGS) are also used in linking.  Many systems
        # supported by AX_PTHREAD require exactly this for POSIX threads
        # support, and in fact it is often not straightforward to specify a
        # flag that is used only in the compilation phase and not in
        # linking.  Such a scenario is extremely rare in practice.
        #
        # Even though use of the -pthread flag in linking would only print
        # a warning, this can be a nuisance for well-run software projects
        # that build with -Werror.  So if the active version of Clang has
        # this misfeature, we search for an option to squash it.

        AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
             # Create an alternate version of $ac_link that compiles and
             # links in two steps (.c -> .o, .o -> exe) instead of one
             # (.c -> exe), because the warning occurs only in the second
             # step
             ax_pthread_save_ac_link="$ac_link"
             ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
             ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
             ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
             ax_pthread_save_CFLAGS="$CFLAGS"
             for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
                AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
                CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
                ac_link="$ax_pthread_save_ac_link"
                AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
                    [ac_link="$ax_pthread_2step_ac_link"
                     AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
                         [break])
                    ])
             done
             ac_link="$ax_pthread_save_ac_link"
             CFLAGS="$ax_pthread_save_CFLAGS"
             AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
             ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
            ])

        case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
                no | unknown) ;;
                *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
        esac

fi # $ax_pthread_clang = yes



# Various other checks:
if test "x$ax_pthread_ok" = "xyes"; then
        ax_pthread_save_CFLAGS="$CFLAGS"
        ax_pthread_save_LIBS="$LIBS"
        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
        LIBS="$PTHREAD_LIBS $LIBS"

        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
        AC_CACHE_CHECK([for joinable pthread attribute],
            [ax_cv_PTHREAD_JOINABLE_ATTR],
            [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
             for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
                 AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],
                                                 [int attr = $ax_pthread_attr; return attr /* ; */])],
                                [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
                                [])
             done
            ])
        AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
               test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
               test "x$ax_pthread_joinable_attr_defined" != "xyes"],
              [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
                                  [$ax_cv_PTHREAD_JOINABLE_ATTR],
                                  [Define to necessary symbol if this constant
                                   uses a non-standard name on your system.])
               ax_pthread_joinable_attr_defined=yes
              ])

        AC_CACHE_CHECK([whether more special flags are required for pthreads],
            [ax_cv_PTHREAD_SPECIAL_FLAGS],
            [ax_cv_PTHREAD_SPECIAL_FLAGS=no
             case $host_os in
             solaris*)
             ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
             ;;
             esac
            ])
        AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
               test "x$ax_pthread_special_flags_added" != "xyes"],
              [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
               ax_pthread_special_flags_added=yes])

        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
            [ax_cv_PTHREAD_PRIO_INHERIT],
            [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],
                                             [[int i = PTHREAD_PRIO_INHERIT;
                                               return i;]])],
                            [ax_cv_PTHREAD_PRIO_INHERIT=yes],
                            [ax_cv_PTHREAD_PRIO_INHERIT=no])
            ])
        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
               test "x$ax_pthread_prio_inherit_defined" != "xyes"],
              [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
               ax_pthread_prio_inherit_defined=yes
              ])

        CFLAGS="$ax_pthread_save_CFLAGS"
        LIBS="$ax_pthread_save_LIBS"

        # More AIX lossage: compile with *_r variant
        if test "x$GCC" != "xyes"; then
            case $host_os in
                aix*)
                AS_CASE(["x/$CC"],
                    [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
                    [#handle absolute path differently from PATH based program lookup
                     AS_CASE(["x$CC"],
                         [x/*],
                         [
			   AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
			   AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
			 ],
                         [
			   AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
			   AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
			 ]
                     )
                    ])
                ;;
            esac
        fi
fi

test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"

AC_SUBST([PTHREAD_LIBS])
AC_SUBST([PTHREAD_CFLAGS])
AC_SUBST([PTHREAD_CC])
AC_SUBST([PTHREAD_CXX])

# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test "x$ax_pthread_ok" = "xyes"; then
        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
        :
else
        ax_pthread_ok=no
        $2
fi
AC_LANG_POP
])dnl AX_PTHREAD
gperftools-gperftools-2.18/m4/program_invocation_name.m4000066400000000000000000000012251513545575200235100ustar00rootroot00000000000000# We need to be careful to avoid having the reference to
# program_invocation_name optimized out.  We do that by
# returning the value.

AC_DEFUN([AC_PROGRAM_INVOCATION_NAME],
  [AC_CACHE_CHECK(
    for program_invocation_name,
    ac_cv_have_program_invocation_name,
    AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern char* program_invocation_name;]], [[return *program_invocation_name;]])],[ac_cv_have_program_invocation_name=yes],[ac_cv_have_program_invocation_name=no])
   )
   if test "$ac_cv_have_program_invocation_name" = "yes"; then
     AC_DEFINE(HAVE_PROGRAM_INVOCATION_NAME, 1,
               [define if libc has program_invocation_name])
   fi
   ])
   
gperftools-gperftools-2.18/src/000077500000000000000000000000001513545575200166155ustar00rootroot00000000000000gperftools-gperftools-2.18/src/addressmap-inl.h000066400000000000000000000364721513545575200217050ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// A fast map from addresses to values.  Assumes that addresses are
// clustered.  The main use is intended to be for heap-profiling.
// May be too memory-hungry for other uses.
//
// We use a user-defined allocator/de-allocator so that we can use
// this data structure during heap-profiling.
//
// IMPLEMENTATION DETAIL:
//
// Some default definitions/parameters:
//  * Block      -- aligned 128-byte region of the address space
//  * Cluster    -- aligned 1-MB region of the address space
//  * Block-ID   -- block-number within a cluster
//  * Cluster-ID -- Starting address of cluster divided by cluster size
//
// We use a three-level map to represent the state:
//  1. A hash-table maps from a cluster-ID to the data for that cluster.
//  2. For each non-empty cluster we keep an array indexed by
//     block-ID tht points to the first entry in the linked-list
//     for the block.
//  3. At the bottom, we keep a singly-linked list of all
//     entries in a block (for non-empty blocks).
//
//    hash table
//  +-------------+
//  | id->cluster |---> ...
//  |     ...     |
//  | id->cluster |--->  Cluster
//  +-------------+     +-------+    Data for one block
//                      |  nil  |   +------------------------------------+
//                      |   ----+---|->[addr/value]-->[addr/value]-->... |
//                      |  nil  |   +------------------------------------+
//                      |   ----+--> ...
//                      |  nil  |
//                      |  ...  |
//                      +-------+
//
// Note that we require zero-bytes of overhead for completely empty
// clusters.  The minimum space requirement for a cluster is the size
// of the hash-table entry plus a pointer value for each block in
// the cluster.  Empty blocks impose no extra space requirement.
//
// The cost of a lookup is:
//      a. A hash-table lookup to find the cluster
//      b. An array access in the cluster structure
//      c. A traversal over the linked-list for a block

#ifndef BASE_ADDRESSMAP_INL_H_
#define BASE_ADDRESSMAP_INL_H_

#include "config.h"

#include 
#include 
#include 
#include 

#include "base/function_ref.h"

// This class is thread-unsafe -- that is, instances of this class can
// not be accessed concurrently by multiple threads -- because the
// callback function for Iterate() may mutate contained values. If the
// callback functions you pass do not mutate their Value* argument,
// AddressMap can be treated as thread-compatible -- that is, it's
// safe for multiple threads to call "const" methods on this class,
// but not safe for one thread to call const methods on this class
// while another thread is calling non-const methods on the class.
template 
class AddressMap {
 public:
  typedef void* (*Allocator)(size_t size);
  typedef void  (*DeAllocator)(void* ptr);
  typedef const void* Key;

  // Create an AddressMap that uses the specified allocator/deallocator.
  // The allocator/deallocator should behave like malloc/free.
  // For instance, the allocator does not need to return initialized memory.
  AddressMap(Allocator alloc, DeAllocator dealloc);
  ~AddressMap();

  // If the map contains an entry for "key", return it. Else return nullptr.
  inline const Value* Find(Key key) const;
  inline Value* FindMutable(Key key);

  // Insert  into the map.  Any old value associated
  // with key is forgotten.
  void Insert(Key key, Value value);

  // Remove any entry for key in the map.  If an entry was found
  // and removed, stores the associated value in "*removed_value"
  // and returns true.  Else returns false.
  bool FindAndRemove(Key key, Value* removed_value);

  // Similar to Find but we assume that keys are addresses of non-overlapping
  // memory ranges whose sizes are given by size_func.
  // If the map contains a range into which "key" points
  // (at its start or inside of it, but not at the end),
  // return the address of the associated value
  // and store its key in "*res_key".
  // Else return nullptr.
  // max_size specifies largest range size possibly in existence now.
  typedef size_t (*ValueSizeFunc)(const Value& v);
  const Value* FindInside(ValueSizeFunc size_func, size_t max_size,
                          Key key, Key* res_key);

  // Iterate over the address map calling 'callback'
  // for all stored key-value pairs and passing 'arg' to it.
  void Iterate(tcmalloc::FunctionRef body) const;

 private:
  typedef uintptr_t Number;

  // The implementation assumes that addresses inserted into the map
  // will be clustered.  We take advantage of this fact by splitting
  // up the address-space into blocks and using a linked-list entry
  // for each block.

  // Size of each block.  There is one linked-list for each block, so
  // do not make the block-size too big.  Oterwise, a lot of time
  // will be spent traversing linked lists.
  static const int kBlockBits = 7;
  static const int kBlockSize = 1 << kBlockBits;

  // Entry kept in per-block linked-list
  struct Entry {
    Entry* next;
    Key    key;
    Value  value;
  };

  // We further group a sequence of consecutive blocks into a cluster.
  // The data for a cluster is represented as a dense array of
  // linked-lists, one list per contained block.
  static const int kClusterBits = 13;
  static const Number kClusterSize = 1 << (kBlockBits + kClusterBits);
  static const int kClusterBlocks = 1 << kClusterBits;

  // We use a simple chaining hash-table to represent the clusters.
  struct Cluster {
    Cluster* next;                      // Next cluster in hash table chain
    Number   id;                        // Cluster ID
    Entry*   blocks[kClusterBlocks];    // Per-block linked-lists
  };

  // Number of hash-table entries.  With the block-size/cluster-size
  // defined above, each cluster covers 1 MB, so an 4K entry
  // hash-table will give an average hash-chain length of 1 for 4GB of
  // in-use memory.
  static const int kHashBits = 12;
  static const int kHashSize = 1 << 12;

  // Number of entry objects allocated at a time
  static const int ALLOC_COUNT = 64;

  Cluster**     hashtable_;              // The hash-table
  Entry*        free_;                   // Free list of unused Entry objects

  // Multiplicative hash function:
  // The value "kHashMultiplier" is the bottom 32 bits of
  //    int((sqrt(5)-1)/2 * 2^32)
  // This is a good multiplier as suggested in CLR, Knuth.  The hash
  // value is taken to be the top "k" bits of the bottom 32 bits
  // of the muliplied value.
  static const uint32_t kHashMultiplier = 2654435769u;
  static int HashInt(Number x) {
    // Multiply by a constant and take the top bits of the result.
    const uint32_t m = static_cast(x) * kHashMultiplier;
    return static_cast(m >> (32 - kHashBits));
  }

  // Find cluster object for specified address.  If not found
  // and "create" is true, create the object.  If not found
  // and "create" is false, return nullptr.
  //
  // This method is bitwise-const if create is false.
  Cluster* FindCluster(Number address, bool create) {
    // Look in hashtable
    const Number cluster_id = address >> (kBlockBits + kClusterBits);
    const int h = HashInt(cluster_id);
    for (Cluster* c = hashtable_[h]; c != nullptr; c = c->next) {
      if (c->id == cluster_id) {
        return c;
      }
    }

    // Create cluster if necessary
    if (create) {
      Cluster* c = New(1);
      c->id = cluster_id;
      c->next = hashtable_[h];
      hashtable_[h] = c;
      return c;
    }
    return nullptr;
  }

  // Return the block ID for an address within its cluster
  static int BlockID(Number address) {
    return (address >> kBlockBits) & (kClusterBlocks - 1);
  }

  //--------------------------------------------------------------
  // Memory management -- we keep all objects we allocate linked
  // together in a singly linked list so we can get rid of them
  // when we are all done.  Furthermore, we allow the client to
  // pass in custom memory allocator/deallocator routines.
  //--------------------------------------------------------------
  struct Object {
    Object* next;
    // The real data starts here
  };

  Allocator     alloc_;                 // The allocator
  DeAllocator   dealloc_;               // The deallocator
  Object*       allocated_;             // List of allocated objects

  // Allocates a zeroed array of T with length "num".  Also inserts
  // the allocated block into a linked list so it can be deallocated
  // when we are all done.
  template  T* New(int num) {
    void* ptr = (*alloc_)(sizeof(Object) + num*sizeof(T));
    memset(ptr, 0, sizeof(Object) + num*sizeof(T));
    Object* obj = reinterpret_cast(ptr);
    obj->next = allocated_;
    allocated_ = obj;
    return reinterpret_cast(reinterpret_cast(ptr) + 1);
  }
};

// More implementation details follow:

template 
AddressMap::AddressMap(Allocator alloc, DeAllocator dealloc)
  : free_(nullptr),
    alloc_(alloc),
    dealloc_(dealloc),
    allocated_(nullptr) {
  hashtable_ = New(kHashSize);
}

template 
AddressMap::~AddressMap() {
  // De-allocate all of the objects we allocated
  for (Object* obj = allocated_; obj != nullptr; /**/) {
    Object* next = obj->next;
    (*dealloc_)(obj);
    obj = next;
  }
}

template 
inline const Value* AddressMap::Find(Key key) const {
  return const_cast(this)->FindMutable(key);
}

template 
inline Value* AddressMap::FindMutable(Key key) {
  const Number num = reinterpret_cast(key);
  const Cluster* const c = FindCluster(num, false/*do not create*/);
  if (c != nullptr) {
    for (Entry* e = c->blocks[BlockID(num)]; e != nullptr; e = e->next) {
      if (e->key == key) {
        return &e->value;
      }
    }
  }
  return nullptr;
}

template 
void AddressMap::Insert(Key key, Value value) {
  const Number num = reinterpret_cast(key);
  Cluster* const c = FindCluster(num, true/*create*/);

  // Look in linked-list for this block
  const int block = BlockID(num);
  for (Entry* e = c->blocks[block]; e != nullptr; e = e->next) {
    if (e->key == key) {
      e->value = value;
      return;
    }
  }

  // Create entry
  if (free_ == nullptr) {
    // Allocate a new batch of entries and add to free-list
    Entry* array = New(ALLOC_COUNT);
    for (int i = 0; i < ALLOC_COUNT-1; i++) {
      array[i].next = &array[i+1];
    }
    array[ALLOC_COUNT-1].next = free_;
    free_ = &array[0];
  }
  Entry* e = free_;
  free_ = e->next;
  e->key = key;
  e->value = value;
  e->next = c->blocks[block];
  c->blocks[block] = e;
}

template 
bool AddressMap::FindAndRemove(Key key, Value* removed_value) {
  const Number num = reinterpret_cast(key);
  Cluster* const c = FindCluster(num, false/*do not create*/);
  if (c != nullptr) {
    for (Entry** p = &c->blocks[BlockID(num)]; *p != nullptr; p = &(*p)->next) {
      Entry* e = *p;
      if (e->key == key) {
        *removed_value = e->value;
        *p = e->next;         // Remove e from linked-list
        e->next = free_;      // Add e to free-list
        free_ = e;
        return true;
      }
    }
  }
  return false;
}

template 
const Value* AddressMap::FindInside(ValueSizeFunc size_func,
                                           size_t max_size,
                                           Key key,
                                           Key* res_key) {
  const Number key_num = reinterpret_cast(key);
  Number num = key_num;  // we'll move this to move back through the clusters
  while (1) {
    const Cluster* c = FindCluster(num, false/*do not create*/);
    if (c != nullptr) {
      while (1) {
        const int block = BlockID(num);
        bool had_smaller_key = false;
        for (const Entry* e = c->blocks[block]; e != nullptr; e = e->next) {
          const Number e_num = reinterpret_cast(e->key);
          if (e_num <= key_num) {
            if (e_num == key_num  ||  // to handle 0-sized ranges
                key_num < e_num + (*size_func)(e->value)) {
              *res_key = e->key;
              return &e->value;
            }
            had_smaller_key = true;
          }
        }
        if (had_smaller_key) return nullptr;  // got a range before
                                              // 'key' and it did not
                                              // contain 'key'
        if (block == 0) break;
        // try address-wise previous block
        num |= kBlockSize - 1;  // start at the last addr of prev block
        num -= kBlockSize;
        if (key_num - num > max_size) return nullptr;
      }
    }
    if (num < kClusterSize) return nullptr;  // first cluster
    // go to address-wise previous cluster to try
    num |= kClusterSize - 1;  // start at the last block of previous cluster
    num -= kClusterSize;
    if (key_num - num > max_size) return nullptr;
      // Having max_size to limit the search is crucial: else
      // we have to traverse a lot of empty clusters (or blocks).
      // We can avoid needing max_size if we put clusters into
      // a search tree, but performance suffers considerably
      // if we use this approach by using stl::set.
  }
}

template 
void AddressMap::Iterate(tcmalloc::FunctionRef body) const {
  // We could optimize this by traversing only non-empty clusters and/or blocks
  // but it does not speed up heap-checker noticeably.
  for (int h = 0; h < kHashSize; ++h) {
    for (const Cluster* c = hashtable_[h]; c != nullptr; c = c->next) {
      for (int b = 0; b < kClusterBlocks; ++b) {
        for (Entry* e = c->blocks[b]; e != nullptr; e = e->next) {
          body(e->key, &e->value);
        }
      }
    }
  }
}

#endif  // BASE_ADDRESSMAP_INL_H_
gperftools-gperftools-2.18/src/base/000077500000000000000000000000001513545575200175275ustar00rootroot00000000000000gperftools-gperftools-2.18/src/base/basictypes.h000066400000000000000000000154651513545575200220610ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef _BASICTYPES_H_
#define _BASICTYPES_H_

#include 
#include        // for memcpy()
#include      // gets us PRId64, etc

#include 
#include 

// Define the "portable" printf and scanf macros, if they're not
// already there (via the inttypes.h we #included above, hopefully).
// Mostly it's old systems that don't support inttypes.h, so we assume
// they're 32 bit.
#ifndef PRIx64
#define PRIx64 "llx"
#endif
#ifndef SCNx64
#define SCNx64 "llx"
#endif
#ifndef PRId64
#define PRId64 "lld"
#endif
#ifndef SCNd64
#define SCNd64 "lld"
#endif
#ifndef PRIu64
#define PRIu64 "llu"
#endif
#ifndef PRIxPTR
#define PRIxPTR "lx"
#endif

#if defined(__GNUC__)
#define PREDICT_TRUE(x) __builtin_expect(!!(x), 1)
#define PREDICT_FALSE(x) __builtin_expect(!!(x), 0)
#else
#define PREDICT_TRUE(x) (x)
#define PREDICT_FALSE(x) (x)
#endif

// A macro to disallow the evil copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \
  TypeName(const TypeName&);                    \
  void operator=(const TypeName&)

// An alternate name that leaves out the moral judgment... :-)
#define DISALLOW_COPY_AND_ASSIGN(TypeName) DISALLOW_EVIL_CONSTRUCTORS(TypeName)

#ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_UNUSED __attribute__((unused))
#else
# define ATTRIBUTE_UNUSED
#endif

#if defined(HAVE___ATTRIBUTE__)
#define ATTR_INITIAL_EXEC __attribute__ ((tls_model ("initial-exec")))
#else
#define ATTR_INITIAL_EXEC
#endif

#define arraysize(a)  (sizeof(a) / sizeof(*(a)))

#define OFFSETOF_MEMBER(strct, field)                                   \
   (reinterpret_cast(&reinterpret_cast(16)->field) -     \
    reinterpret_cast(16))

// bit_cast implements the equivalent of
// "*reinterpret_cast(&source)".
//
// The reinterpret_cast method would produce undefined behavior
// according to ISO C++ specification section 3.10 -15 -.
// bit_cast<> calls memcpy() which is blessed by the standard,
// especially by the example in section 3.9.
//
// Fortunately memcpy() is very fast.  In optimized mode, with a
// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
// code with the minimal amount of data movement.  On a 32-bit system,
// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
// compiles to two loads and two stores.

template 
inline Dest bit_cast(const Source& source) {
  static_assert(sizeof(Dest) == sizeof(Source), "bitcasting unequal sizes");
  Dest dest;
  memcpy(&dest, &source, sizeof(dest));
  return dest;
}

// bit_store implements the equivalent of
// "dest = *reinterpret_cast(&source)".
//
// This prevents undefined behavior when the dest pointer is unaligned.
template 
inline void bit_store(Dest *dest, const Source *source) {
  static_assert(sizeof(Dest) == sizeof(Source), "bitcasting unequal sizes");
  memcpy(dest, source, sizeof(Dest));
}

#ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_WEAK      __attribute__((weak))
# define ATTRIBUTE_NOINLINE  __attribute__((noinline))
#else
# define ATTRIBUTE_WEAK
# define ATTRIBUTE_NOINLINE
#endif

#ifdef _MSC_VER
#undef ATTRIBUTE_NOINLINE
#define ATTRIBUTE_NOINLINE __declspec(noinline)
#endif

#if defined(HAVE___ATTRIBUTE__) && defined(__ELF__) && !defined(TCMALLOC_DISABLE_HIDDEN_VISIBILITY)
# define ATTRIBUTE_VISIBILITY_HIDDEN __attribute__((visibility("hidden")))
#else
# define ATTRIBUTE_VISIBILITY_HIDDEN
#endif

#if defined(HAVE___ATTRIBUTE__)
# if (defined(__i386__) || defined(__x86_64__))
#   define CACHELINE_ALIGNED __attribute__((aligned(64)))
# elif (defined(__PPC__) || defined(__PPC64__) || defined(__ppc__) || defined(__ppc64__))
#   define CACHELINE_ALIGNED __attribute__((aligned(16)))
# elif (defined(__arm__))
#   define CACHELINE_ALIGNED __attribute__((aligned(64)))
    // some ARMs have shorter cache lines (ARM1176JZF-S is 32 bytes for example) but obviously 64-byte aligned implies 32-byte aligned
# elif (defined(__mips__))
#   define CACHELINE_ALIGNED __attribute__((aligned(128)))
# elif (defined(__aarch64__))
#   define CACHELINE_ALIGNED __attribute__((aligned(64)))
    // implementation specific, Cortex-A53 and 57 should have 64 bytes
# elif (defined(__s390__))
#   define CACHELINE_ALIGNED __attribute__((aligned(256)))
# elif (defined(__riscv) && __riscv_xlen == 64)
#   define CACHELINE_ALIGNED __attribute__((aligned(64)))
# elif defined(__loongarch64)
#   define CACHELINE_ALIGNED __attribute__((aligned(64)))
# elif defined(__sparcv9) || defined(__sparcv9__)
#   define CACHELINE_ALIGNED __attribute__((aligned(64)))
# else
#   error Could not determine cache line length - unknown architecture
# endif
#else
# define CACHELINE_ALIGNED
#endif  // defined(HAVE___ATTRIBUTE__)

#if defined(HAVE___ATTRIBUTE__ALIGNED_FN)
#  define CACHELINE_ALIGNED_FN CACHELINE_ALIGNED
#else
#  define CACHELINE_ALIGNED_FN
#endif

// Structure for discovering alignment
union MemoryAligner {
  void*  p;
  double d;
  size_t s;
} CACHELINE_ALIGNED;

#if defined(__GNUC__)
#define ALWAYS_INLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER)
#define ALWAYS_INLINE __forceinline
#else
#define ALWAYS_INLINE inline
#endif

#endif  // _BASICTYPES_H_
gperftools-gperftools-2.18/src/base/cleanup.h000066400000000000000000000056111513545575200213320ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef BASE_CLEANUP_H_
#define BASE_CLEANUP_H_
#include "config.h"

#include 
#include 

namespace tcmalloc {

// Cleanup represents a piece of work (like closing file descriptor)
// when it's scope ends. Anything that can be invoked, and returns
// null can be used. Most typical callback is lambda. This is somewhat
// similar to Go's defer statement.
//
// This is direct equivalent of abseil's absl::Cleanup, except ours
// cannot be moved from (use std::optional if you need this) and
// cannot be canceled. And is much simpler as a result.
//
// Note, we don't offer equivalent of absl::MakeCleanup. Instead, we
// encourage use of C++17 class template argument deduction. I.e. use
// like this:
//
// tcmalloc::Cleanup cleanup([&] () { fclose(something); });
template 
class Cleanup {
public:
  static_assert(std::is_same, void>::value,
                "Cleanup callback must return void");

  explicit Cleanup(Callback callback) : callback_(std::move(callback)) {}

  // We don't support copying or moving those
  Cleanup(const Cleanup& other) = delete;
  Cleanup& operator=(const Cleanup& other) = delete;

  ~Cleanup() {
    callback_();
  }

private:
  Callback callback_;
};

}  // namespace tcmalloc

#endif  // BASE_CLEANUP_H_
gperftools-gperftools-2.18/src/base/commandlineflags.h000066400000000000000000000155221513545575200232100ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// This file is a compatibility layer that defines Google's version of
// command line flags that are used for configuration.
//
// We put flags into their own namespace.  It is purposefully
// named in an opaque way that people should have trouble typing
// directly.  The idea is that DEFINE puts the flag in the weird
// namespace, and DECLARE imports the flag from there into the
// current namespace.  The net result is to force people to use
// DECLARE to get access to a flag, rather than saying
//   extern bool FLAGS_logtostderr;
// or some such instead.  We want this so we can put extra
// functionality (like sanity-checking) in DECLARE if we want,
// and make sure it is picked up everywhere.
//
// We also put the type of the variable in the namespace, so that
// people can't DECLARE_int32 something that they DEFINE_bool'd
// elsewhere.
#ifndef BASE_COMMANDLINEFLAGS_H_
#define BASE_COMMANDLINEFLAGS_H_

#include 
#include 
#include                // for memchr
#include                // for getenv
#include "base/basictypes.h"

#define DECLARE_VARIABLE(type, name)                                          \
  namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead {  \
  extern type FLAGS_##name;                                \
  }                                                                           \
  using FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead::FLAGS_##name

#define DEFINE_VARIABLE(type, name, value, meaning) \
  namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead {  \
  type FLAGS_##name(value);                                \
  char FLAGS_no##name;                                                        \
  }                                                                           \
  using FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead::FLAGS_##name

// bool specialization
#define DECLARE_bool(name) \
  DECLARE_VARIABLE(bool, name)
#define DEFINE_bool(name, value, meaning) \
  DEFINE_VARIABLE(bool, name, value, meaning)

// int32_t specialization
#define DECLARE_int32(name) \
  DECLARE_VARIABLE(int32_t, name)
#define DEFINE_int32(name, value, meaning) \
  DEFINE_VARIABLE(int32_t, name, value, meaning)

// int64_t specialization
#define DECLARE_int64(name) \
  DECLARE_VARIABLE(int64_t, name)
#define DEFINE_int64(name, value, meaning) \
  DEFINE_VARIABLE(int64_t, name, value, meaning)

#define DECLARE_uint64(name) \
  DECLARE_VARIABLE(uint64_t, name)
#define DEFINE_uint64(name, value, meaning) \
  DEFINE_VARIABLE(uint64_t, name, value, meaning)

// double specialization
#define DECLARE_double(name) \
  DECLARE_VARIABLE(double, name)
#define DEFINE_double(name, value, meaning) \
  DEFINE_VARIABLE(double, name, value, meaning)

// Special case for string, because we have to specify the namespace
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
#define DECLARE_string(name)                                          \
  namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead {  \
  extern std::string FLAGS_##name;                                                   \
  }                                                                           \
  using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name
#define DEFINE_string(name, value, meaning) \
  namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead {  \
  std::string FLAGS_##name(value);                                                   \
  char FLAGS_no##name;                                                        \
  }                                                                           \
  using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name

// implemented in sysinfo.cc
namespace tcmalloc {
  namespace commandlineflags {

    inline bool StringToBool(const char *value, bool def) {
      if (!value) {
        return def;
      }
      switch (value[0]) {
      case 't':
      case 'T':
      case 'y':
      case 'Y':
      case '1':
      case '\0':
        return true;
      }
      return false;
    }

    inline int StringToInt(const char *value, int def) {
      if (!value) {
        return def;
      }
      return strtol(value, nullptr, 10);
    }

    inline long long StringToLongLong(const char *value, long long def) {
      if (!value) {
        return def;
      }
      return strtoll(value, nullptr, 10);
    }

    inline double StringToDouble(const char *value, double def) {
      if (!value) {
        return def;
      }
      return strtod(value, nullptr);
    }
  }
}

// These macros (could be functions, but I don't want to bother with a .cc
// file), make it easier to initialize flags from the environment.

#define EnvToString(envname, dflt)   \
  (!getenv(envname) ? (dflt) : getenv(envname))

#define EnvToBool(envname, dflt)   \
  tcmalloc::commandlineflags::StringToBool(getenv(envname), dflt)

#define EnvToInt(envname, dflt)  \
  tcmalloc::commandlineflags::StringToInt(getenv(envname), dflt)

#define EnvToInt64(envname, dflt)  \
  tcmalloc::commandlineflags::StringToLongLong(getenv(envname), dflt)

#define EnvToDouble(envname, dflt)  \
  tcmalloc::commandlineflags::StringToDouble(getenv(envname), dflt)

#endif  // BASE_COMMANDLINEFLAGS_H_
gperftools-gperftools-2.18/src/base/dynamic_annotations.cc000066400000000000000000000050651513545575200241050ustar00rootroot00000000000000// -*- Mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2008-2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Kostya Serebryany
 */

#include "config.h"
#include 
#include 

#if defined __has_include
#if __has_include()
#include 
#endif  // __has_include
#endif // defined __has_include

#include "base/dynamic_annotations.h"
#include "getenv_safe.h" // for TCMallocGetenvSafe

static int GetRunningOnValgrind(void) {
#ifdef RUNNING_ON_VALGRIND
  if (RUNNING_ON_VALGRIND) return 1;
#endif
  const char *running_on_valgrind_str = TCMallocGetenvSafe("RUNNING_ON_VALGRIND");
  if (running_on_valgrind_str) {
    return strcmp(running_on_valgrind_str, "0") != 0;
  }
  return 0;
}

/* See the comments in dynamic_annotations.h */
int RunningOnValgrind(void) {
  static volatile int running_on_valgrind = -1;
  int local_running_on_valgrind = running_on_valgrind;
  if (local_running_on_valgrind == -1)
    running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
  return local_running_on_valgrind;
}
gperftools-gperftools-2.18/src/base/dynamic_annotations.h000066400000000000000000000067501513545575200237510ustar00rootroot00000000000000/* -*- Mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* Copyright (c) 2008, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Kostya Serebryany
 */

/* This file defines dynamic annotations for use with dynamic analysis
   tool such as valgrind, PIN, etc.

   Dynamic annotation is a source code annotation that affects
   the generated code (that is, the annotation is not a comment).
   Each such annotation is attached to a particular
   instruction and/or to a particular object (address) in the program.

   The annotations that should be used by users are macros in all upper-case
   (e.g., ANNOTATE_NEW_MEMORY).

   Actual implementation of these macros may differ depending on the
   dynamic analysis tool being used.

   See http://code.google.com/p/data-race-test/  for more information.

   This file supports the following dynamic analysis tools:
   - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero).
      Macros are defined empty.
   - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1).
      Macros are defined as calls to non-inlinable empty functions
      that are intercepted by Valgrind. */

#ifndef BASE_DYNAMIC_ANNOTATIONS_H_
#define BASE_DYNAMIC_ANNOTATIONS_H_

#ifdef __cplusplus
extern "C" {
#endif

/* Return non-zero value if running under valgrind.

  If "valgrind.h" is included into dynamic_annotations.c,
  the regular valgrind mechanism will be used.
  See http://valgrind.org/docs/manual/manual-core-adv.html about
  RUNNING_ON_VALGRIND and other valgrind "client requests".
  The file "valgrind.h" may be obtained by doing
     svn co svn://svn.valgrind.org/valgrind/trunk/include

  If for some reason you can't use "valgrind.h" or want to fake valgrind,
  there are two ways to make this function return non-zero:
    - Use environment variable: export RUNNING_ON_VALGRIND=1
    - Make your tool intercept the function RunningOnValgrind() and
      change its return value.
 */
int RunningOnValgrind(void);

#ifdef __cplusplus
}
#endif

#endif  /* BASE_DYNAMIC_ANNOTATIONS_H_ */
gperftools-gperftools-2.18/src/base/elf_mem_image.cc000066400000000000000000000345151513545575200226140ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Paul Pluzhnikov
//
// Allow dynamic symbol lookup in an in-memory Elf image.
//

#include "base/elf_mem_image.h"

#ifdef HAVE_ELF_MEM_IMAGE  // defined in elf_mem_image.h

#include    // for size_t, ptrdiff_t
#include "base/logging.h"

// From binutils/include/elf/common.h (this doesn't appear to be documented
// anywhere else).
//
//   /* This flag appears in a Versym structure.  It means that the symbol
//      is hidden, and is only visible with an explicit version number.
//      This is a GNU extension.  */
//   #define VERSYM_HIDDEN           0x8000
//
//   /* This is the mask for the rest of the Versym information.  */
//   #define VERSYM_VERSION          0x7fff

#define VERSYM_VERSION 0x7fff

namespace base {

namespace {
template  class ElfClass {
 public:
  static const int kElfClass = -1;
  static int ElfBind(const ElfW(Sym) *) {
    CHECK(false); // << "Unexpected word size";
    return 0;
  }
  static int ElfType(const ElfW(Sym) *) {
    CHECK(false); // << "Unexpected word size";
    return 0;
  }
};

template <> class ElfClass<32> {
 public:
  static const int kElfClass = ELFCLASS32;
  static int ElfBind(const ElfW(Sym) *symbol) {
    return ELF32_ST_BIND(symbol->st_info);
  }
  static int ElfType(const ElfW(Sym) *symbol) {
    return ELF32_ST_TYPE(symbol->st_info);
  }
};

template <> class ElfClass<64> {
 public:
  static const int kElfClass = ELFCLASS64;
  static int ElfBind(const ElfW(Sym) *symbol) {
    return ELF64_ST_BIND(symbol->st_info);
  }
  static int ElfType(const ElfW(Sym) *symbol) {
    return ELF64_ST_TYPE(symbol->st_info);
  }
};

typedef ElfClass<__WORDSIZE> CurrentElfClass;

// Extract an element from one of the ELF tables, cast it to desired type.
// This is just a simple arithmetic and a glorified cast.
// Callers are responsible for bounds checking.
template 
const T* GetTableElement(const ElfW(Ehdr) *ehdr,
                         ElfW(Off) table_offset,
                         ElfW(Word) element_size,
                         size_t index) {
  return reinterpret_cast(reinterpret_cast(ehdr)
                                    + table_offset
                                    + index * element_size);
}
}  // namespace

const void *const ElfMemImage::kInvalidBase =
    reinterpret_cast(~0L);

ElfMemImage::ElfMemImage(const void *base) {
  CHECK(base != kInvalidBase);
  Init(base);
}

int ElfMemImage::GetNumSymbols() const {
  if (!hash_) {
    return 0;
  }
  // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
  return hash_[1];
}

const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
  CHECK_LT(index, GetNumSymbols());
  return dynsym_ + index;
}

const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
  CHECK_LT(index, GetNumSymbols());
  return versym_ + index;
}

const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const {
  CHECK_LT(index, ehdr_->e_phnum);
  return GetTableElement(ehdr_,
                                     ehdr_->e_phoff,
                                     ehdr_->e_phentsize,
                                     index);
}

const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const {
  CHECK_LT(offset, strsize_);
  return dynstr_ + offset;
}

const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
  if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
    // Symbol corresponds to "special" (e.g. SHN_ABS) section.
    return reinterpret_cast(sym->st_value);
  }
  CHECK_LT(link_base_, sym->st_value);
  return GetTableElement(ehdr_, 0, 1, sym->st_value) - link_base_;
}

const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
  CHECK_LE(index, verdefnum_);
  const ElfW(Verdef) *version_definition = verdef_;
  while (version_definition->vd_ndx < index && version_definition->vd_next) {
    const char *const version_definition_as_char =
        reinterpret_cast(version_definition);
    version_definition =
        reinterpret_cast(version_definition_as_char +
                                               version_definition->vd_next);
  }
  return version_definition->vd_ndx == index ? version_definition : nullptr;
}

const ElfW(Verdaux) *ElfMemImage::GetVerdefAux(
    const ElfW(Verdef) *verdef) const {
  return reinterpret_cast(verdef+1);
}

const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const {
  CHECK_LT(offset, strsize_);
  return dynstr_ + offset;
}

void ElfMemImage::Init(const void *base) {
  ehdr_      = nullptr;
  dynsym_    = nullptr;
  dynstr_    = nullptr;
  versym_    = nullptr;
  verdef_    = nullptr;
  hash_      = nullptr;
  strsize_   = 0;
  verdefnum_ = 0;
  link_base_ = ~0L;  // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
  if (!base) {
    return;
  }
  const intptr_t base_as_uintptr_t = reinterpret_cast(base);
  // Fake VDSO has low bit set.
  const bool fake_vdso = ((base_as_uintptr_t & 1) != 0);
  base = reinterpret_cast(base_as_uintptr_t & ~1);
  const char *const base_as_char = reinterpret_cast(base);
  if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
      base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
    RAW_DCHECK(false, "no ELF magic"); // at %p", base);
    return;
  }
  int elf_class = base_as_char[EI_CLASS];
  if (elf_class != CurrentElfClass::kElfClass) {
    DCHECK_EQ(elf_class, CurrentElfClass::kElfClass);
    return;
  }
  switch (base_as_char[EI_DATA]) {
    case ELFDATA2LSB: {
      if (__LITTLE_ENDIAN != __BYTE_ORDER) {
        DCHECK_EQ(__LITTLE_ENDIAN, __BYTE_ORDER); // << ": wrong byte order";
        return;
      }
      break;
    }
    case ELFDATA2MSB: {
      if (__BIG_ENDIAN != __BYTE_ORDER) {
        DCHECK_EQ(__BIG_ENDIAN, __BYTE_ORDER); // << ": wrong byte order";
        return;
      }
      break;
    }
    default: {
      RAW_DCHECK(false, "unexpected data encoding"); // << base_as_char[EI_DATA];
      return;
    }
  }

  ehdr_ = reinterpret_cast(base);
  const ElfW(Phdr) *dynamic_program_header = nullptr;
  for (int i = 0; i < ehdr_->e_phnum; ++i) {
    const ElfW(Phdr) *const program_header = GetPhdr(i);
    switch (program_header->p_type) {
      case PT_LOAD:
        if (link_base_ == ~0L) {
          link_base_ = program_header->p_vaddr;
        }
        break;
      case PT_DYNAMIC:
        dynamic_program_header = program_header;
        break;
    }
  }
  if (link_base_ == ~0L || !dynamic_program_header) {
    RAW_DCHECK(~0L != link_base_, "no PT_LOADs in VDSO");
    RAW_DCHECK(dynamic_program_header, "no PT_DYNAMIC in VDSO");
    // Mark this image as not present. Can not recur infinitely.
    Init(0);
    return;
  }
  ptrdiff_t relocation =
      base_as_char - reinterpret_cast(link_base_);
  ElfW(Dyn) *dynamic_entry =
      reinterpret_cast(dynamic_program_header->p_vaddr +
                                    relocation);
  for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
    ElfW(Xword) value = dynamic_entry->d_un.d_val;
    if (fake_vdso) {
      // A complication: in the real VDSO, dynamic entries are not relocated
      // (it wasn't loaded by a dynamic loader). But when testing with a
      // "fake" dlopen()ed vdso library, the loader relocates some (but
      // not all!) of them before we get here.
      if (dynamic_entry->d_tag == DT_VERDEF) {
        // The only dynamic entry (of the ones we care about) libc-2.3.6
        // loader doesn't relocate.
        value += relocation;
      }
    } else {
      // Real VDSO. Everything needs to be relocated.
      value += relocation;
    }
    switch (dynamic_entry->d_tag) {
      case DT_HASH:
        hash_ = reinterpret_cast(value);
        break;
      case DT_SYMTAB:
        dynsym_ = reinterpret_cast(value);
        break;
      case DT_STRTAB:
        dynstr_ = reinterpret_cast(value);
        break;
      case DT_VERSYM:
        versym_ = reinterpret_cast(value);
        break;
      case DT_VERDEF:
        verdef_ = reinterpret_cast(value);
        break;
      case DT_VERDEFNUM:
        verdefnum_ = dynamic_entry->d_un.d_val;
        break;
      case DT_STRSZ:
        strsize_ = dynamic_entry->d_un.d_val;
        break;
      default:
        // Unrecognized entries explicitly ignored.
        break;
    }
  }
  if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
      !verdef_ || !verdefnum_ || !strsize_) {
    RAW_DCHECK(hash_, "invalid VDSO (no DT_HASH)");
    RAW_DCHECK(dynsym_, "invalid VDSO (no DT_SYMTAB)");
    RAW_DCHECK(dynstr_, "invalid VDSO (no DT_STRTAB)");
    RAW_DCHECK(versym_, "invalid VDSO (no DT_VERSYM)");
    RAW_DCHECK(verdef_, "invalid VDSO (no DT_VERDEF)");
    RAW_DCHECK(verdefnum_, "invalid VDSO (no DT_VERDEFNUM)");
    RAW_DCHECK(strsize_, "invalid VDSO (no DT_STRSZ)");
    // Mark this image as not present. Can not recur infinitely.
    Init(0);
    return;
  }
}

bool ElfMemImage::LookupSymbol(const char *name,
                               const char *version,
                               int type,
                               SymbolInfo *info) const {
  for (SymbolIterator it = begin(); it != end(); ++it) {
    if (strcmp(it->name, name) == 0 && strcmp(it->version, version) == 0 &&
        CurrentElfClass::ElfType(it->symbol) == type) {
      if (info) {
        *info = *it;
      }
      return true;
    }
  }
  return false;
}

bool ElfMemImage::LookupSymbolByAddress(const void *address,
                                        SymbolInfo *info_out) const {
  for (SymbolIterator it = begin(); it != end(); ++it) {
    const char *const symbol_start =
        reinterpret_cast(it->address);
    const char *const symbol_end = symbol_start + it->symbol->st_size;
    if (symbol_start <= address && address < symbol_end) {
      if (info_out) {
        // Client wants to know details for that symbol (the usual case).
        if (CurrentElfClass::ElfBind(it->symbol) == STB_GLOBAL) {
          // Strong symbol; just return it.
          *info_out = *it;
          return true;
        } else {
          // Weak or local. Record it, but keep looking for a strong one.
          *info_out = *it;
        }
      } else {
        // Client only cares if there is an overlapping symbol.
        return true;
      }
    }
  }
  return false;
}

ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
    : index_(index), image_(image) {
}

const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
  return &info_;
}

const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const {
  return info_;
}

bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const {
  return this->image_ == rhs.image_ && this->index_ == rhs.index_;
}

bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
  return !(*this == rhs);
}

ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() {
  this->Update(1);
  return *this;
}

ElfMemImage::SymbolIterator ElfMemImage::begin() const {
  SymbolIterator it(this, 0);
  it.Update(0);
  return it;
}

ElfMemImage::SymbolIterator ElfMemImage::end() const {
  return SymbolIterator(this, GetNumSymbols());
}

void ElfMemImage::SymbolIterator::Update(int increment) {
  const ElfMemImage *image = reinterpret_cast(image_);
  CHECK(image->IsPresent() || increment == 0);
  if (!image->IsPresent()) {
    return;
  }
  index_ += increment;
  if (index_ >= image->GetNumSymbols()) {
    index_ = image->GetNumSymbols();
    return;
  }
  const ElfW(Sym)    *symbol = image->GetDynsym(index_);
  const ElfW(Versym) *version_symbol = image->GetVersym(index_);
  CHECK(symbol && version_symbol);
  const char *const symbol_name = image->GetDynstr(symbol->st_name);
  const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION;
  const ElfW(Verdef) *version_definition = nullptr;
  const char *version_name = "";
  if (symbol->st_shndx == SHN_UNDEF) {
    // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and
    // version_index could well be greater than verdefnum_, so calling
    // GetVerdef(version_index) may trigger assertion.
  } else {
    version_definition = image->GetVerdef(version_index);
  }
  if (version_definition) {
    // I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
    // optional 2nd if the version has a parent.
    CHECK_LE(1, version_definition->vd_cnt);
    CHECK_LE(version_definition->vd_cnt, 2);
    const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
    version_name = image->GetVerstr(version_aux->vda_name);
  }
  info_.name    = symbol_name;
  info_.version = version_name;
  info_.address = image->GetSymAddr(symbol);
  info_.symbol  = symbol;
}

}  // namespace base

#endif  // HAVE_ELF_MEM_IMAGE
gperftools-gperftools-2.18/src/base/elf_mem_image.h000066400000000000000000000116521513545575200224530ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Paul Pluzhnikov
//
// Allow dynamic symbol lookup for in-memory Elf images.

#ifndef BASE_ELF_MEM_IMAGE_H_
#define BASE_ELF_MEM_IMAGE_H_

#include 

// Note, in gperftools we only use it on GNU/Linux PPC and nowhere
// else.
#if defined(__linux__) && defined(__PPC__)

#define HAVE_ELF_MEM_IMAGE 1

#include 
#include   // for ElfW

namespace base {

// An in-memory ELF image (may not exist on disk).
class ElfMemImage {
 public:
  // Sentinel: there could never be an elf image at this address.
  static const void *const kInvalidBase;

  // Information about a single vdso symbol.
  // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
  // Do not free() them or modify through them.
  struct SymbolInfo {
    const char      *name;      // E.g. "__vdso_getcpu"
    const char      *version;   // E.g. "LINUX_2.6", could be ""
                                // for unversioned symbol.
    const void      *address;   // Relocated symbol address.
    const ElfW(Sym) *symbol;    // Symbol in the dynamic symbol table.
  };

  // Supports iteration over all dynamic symbols.
  class SymbolIterator {
   public:
    friend class ElfMemImage;
    const SymbolInfo *operator->() const;
    const SymbolInfo &operator*() const;
    SymbolIterator& operator++();
    bool operator!=(const SymbolIterator &rhs) const;
    bool operator==(const SymbolIterator &rhs) const;
   private:
    SymbolIterator(const void *const image, int index);
    void Update(int incr);
    SymbolInfo info_;
    int index_;
    const void *const image_;
  };


  explicit ElfMemImage(const void *base);
  void                 Init(const void *base);
  bool                 IsPresent() const { return ehdr_ != nullptr; }
  const ElfW(Phdr)*    GetPhdr(int index) const;
  const ElfW(Sym)*     GetDynsym(int index) const;
  const ElfW(Versym)*  GetVersym(int index) const;
  const ElfW(Verdef)*  GetVerdef(int index) const;
  const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
  const char*          GetDynstr(ElfW(Word) offset) const;
  const void*          GetSymAddr(const ElfW(Sym) *sym) const;
  const char*          GetVerstr(ElfW(Word) offset) const;
  int                  GetNumSymbols() const;

  SymbolIterator begin() const;
  SymbolIterator end() const;

  // Look up versioned dynamic symbol in the image.
  // Returns false if image is not present, or doesn't contain given
  // symbol/version/type combination.
  // If info_out != nullptr, additional details are filled in.
  bool LookupSymbol(const char *name, const char *version,
                    int symbol_type, SymbolInfo *info_out) const;

  // Find info about symbol (if any) which overlaps given address.
  // Returns true if symbol was found; false if image isn't present
  // or doesn't have a symbol overlapping given address.
  // If info_out != nullptr, additional details are filled in.
  bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;

 private:
  const ElfW(Ehdr) *ehdr_;
  const ElfW(Sym) *dynsym_;
  const ElfW(Versym) *versym_;
  const ElfW(Verdef) *verdef_;
  const ElfW(Word) *hash_;
  const char *dynstr_;
  size_t strsize_;
  size_t verdefnum_;
  ElfW(Addr) link_base_;     // Link-time base (p_vaddr of first PT_LOAD).
};

}  // namespace base

#endif  // __ELF__ and __GLIBC__ and !__native_client__

#endif  // BASE_ELF_MEM_IMAGE_H_
gperftools-gperftools-2.18/src/base/environ.h000066400000000000000000000044341513545575200213650ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2025, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef ENVIRON_H
#define ENVIRON_H
#include 

#ifdef _WIN32
#undef environ
#define environ _environ
#endif  // _WIN32

// POSIX standard oddly requires users to define environ variable
// themselves. 3 of 3 bsd-derived systems I tested on actually
// don't bother having environ in their headers. Relevant ticket has
// been closed as "won't fix" in FreeBSD ticket tracker:
// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=238672
//
// Just in case, we wrap this declaration with ifdef, so that if
// anyone has environ as macro (see windows case above), we won't be
// breaking anything.
#if !defined(environ)
extern "C" {
extern char** environ;
}
#endif

#endif  // ENVIRON_H
gperftools-gperftools-2.18/src/base/for_each_line.h000066400000000000000000000074301513545575200224610ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2025, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef FOR_EACH_LINE_H_
#define FOR_EACH_LINE_H_
#include "config.h"

#include 

#include "base/basictypes.h"
#include "base/function_ref.h"
#include "base/logging.h"

namespace tcmalloc {

// Using buffer of the given size, reads some contents, find lines
// boundaries and calls given body function for each line. We assume
// that BufSize is large enough to hold largest line. If we see line
// that is longer than the buffer, we fail and return false.
template 
ATTRIBUTE_VISIBILITY_HIDDEN
bool ForEachLine(FunctionRef reader, FunctionRef body) {
  char buf[BufSize];
  char* const buf_end = buf + sizeof(buf) - 1;

  char* sbuf = buf; // note, initial value could be nullptr, but
                    // memmove actually insists to get non-null
                    // arguments (even when count is 0)
  char* ebuf = sbuf;

  bool eof = false;

  for (;;) {
    char* nextline = static_cast(memchr(sbuf, '\n', ebuf - sbuf));

    if (nextline != nullptr) {
      RAW_CHECK(nextline < ebuf, "BUG");

      *nextline = 0; // Turn newline into '\0'.

      if (!body(sbuf, nextline)) {
        break;
      }

      sbuf = nextline + 1;
      continue;
    }

    int count = ebuf - sbuf;

    if (eof) {
      if (count == 0) {
        break; // done
      }

      // Last read ended up without trailing newline. Lets add
      // it. Note, we left one byte margin above, so we're able to
      // write this and not get past end of buf.
      *ebuf++ = '\n';
      continue;
    }

    if (ebuf == buf_end && sbuf == buf) {
      // Line somehow ended up too long for our buffer. Bail out.
      return false;
    }

    // Move the current text to the start of the buffer
    memmove(buf, sbuf, count);
    sbuf = buf;
    ebuf = sbuf + count;

    int nread = reader(ebuf, buf_end - ebuf);

    // Read failures are not expected, but lets not crash if this
    // happens in non-debug mode.
    DCHECK_GE(nread, 0);
    if (nread < 0) {
      nread = 0;
    }

    if (nread == 0) {
      eof = true;
    }
    ebuf += nread;
    // Retry memchr above.
  }

  return true;
}

}  // namespace tcmalloc

#endif  // FOR_EACH_LINE_H_

gperftools-gperftools-2.18/src/base/function_ref.h000066400000000000000000000111101513545575200223530ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef BASE_FUNCTION_REF_H_
#define BASE_FUNCTION_REF_H_
#include "config.h"

#include 
#include 

namespace tcmalloc {

template 
struct FunctionRef;

// FunctionRef is to std::function what std::string_view is to
// std::string. That is non-owning, trivially copyable reference-like
// type to anything that can be invoked. It is mostly equivalent to
// absl::FunctionRef. Just like std::string_view we encourage people
// to pass it by value and in most most modern ABIs it will be
// efficiently passed in two registers.
//
// It avoids any memory allocation (unlike std::function). So good to
// use everywhere even inside tightest guts of malloc or
// super-early. Of course, since it doesn't own it's invokable, it
// must not outlive it.
//
// Our version also explicitly exposes pure C-style function and data
// arguments to be used by legacy C-style API's that pass callback
// function and callback argument in order to implement closure-like
// features.
template 
struct FunctionRef {
  template >
  using EnableIfCompatible =
      typename std::enable_if::value ||
                              std::is_convertible::value>::type;

  explicit FunctionRef(R (*fn)(Args..., void*), void* data)
    : fn(fn), data(data) {}

  template >
  FunctionRef(const Body& body) : FunctionRef(
    [] (Args... args, void* data) {
      const Body& b = *(reinterpret_cast(data));
      return b(std::forward(args)...);
    },
    const_cast(reinterpret_cast(&body))) {}

  R operator()(Args... args) const {
    return fn(std::forward(args)..., data);
  }

  R (*const fn)(Args... args, void* data);
  void* const data;
};

template 
struct FunctionRefFirstDataArg;

// FunctionRefFirstDataArg is same as FunctionRef except it's fn's
// function type accepts data argument in first position.
template 
struct FunctionRefFirstDataArg {
  template >
  using EnableIfCompatible =
      typename std::enable_if::value ||
                              std::is_convertible::value>::type;

  explicit FunctionRefFirstDataArg(R (*fn)(void*, Args...), void* data)
    : fn(fn), data(data) {}

  template 
  FunctionRefFirstDataArg(const Body& body) : FunctionRefFirstDataArg(
    [] (void* data, Args... args) {
      const Body& b = *(reinterpret_cast(data));
      return b(std::forward(args)...);
    },
    const_cast(reinterpret_cast(&body))) {}

  R operator()(Args... args) const {
    return fn(data, std::forward(args)...);
  }

  R (*const fn)(void* data, Args... args);
  void* const data;
};

}  // namespace tcmalloc

#endif  // BASE_FUNCTION_REF_H_
gperftools-gperftools-2.18/src/base/generic_writer.cc000066400000000000000000000155011513545575200230500ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "base/generic_writer.h"

#include 
#include 
#include 

namespace tcmalloc {

GenericWriter::~GenericWriter() {
  RAW_DCHECK(buf_ == buf_fill_, "writer has to be finalized by call to FinalRecycle()");
}

void GenericWriter::AppendF(const char* fmt, ...) {
  int space_left = buf_end_ - buf_fill_;

  va_list va;
  va_start(va, fmt);
  int written = vsnprintf(buf_fill_, space_left, fmt, va);
  va_end(va);

  if (PREDICT_FALSE(written >= space_left)) {
    std::tie(buf_, buf_end_) = RecycleBuffer(buf_, buf_fill_, written + 1);
    RAW_DCHECK(written < buf_end_ - buf_, "recycled buffer needs to have space for this append");
    buf_fill_ = buf_;

    va_list va;
    va_start(va, fmt);
    space_left = buf_end_ - buf_;
    written = vsnprintf(buf_, space_left, fmt, va);
    va_end(va);

    RAW_DCHECK(written < space_left, "");
    // In case condition above holds (which we only test in debug builds)
    written = std::min(written, space_left - 1);
  }

  buf_fill_ += written;
}

void GenericWriter::AppendMem(const char* str, size_t sz) {
  for (;;) {
    // first, cap amount to be at most MAX_INT
    int amount = static_cast(std::min(std::numeric_limits::max(), sz));
    amount = std::min(amount, buf_end_ - buf_fill_);

    // So this is silly but ultimately harmless. Glibc defines memcpy
    // args to be non-null (so, even for the amount == 0 case). And
    // while in practice it works (and has to), ubsan kinda complains.
    //
    // Thankfully in this place we can afford slight perf hit of doing
    // "stupid" thing.
    if (PREDICT_TRUE(amount != 0)) {
      memcpy(buf_fill_, str, amount);
    }

    str += amount;
    buf_fill_ += amount;
    sz -= amount;

    if (sz == 0) {
      return;
    }

    std::tie(buf_, buf_end_) = RecycleBuffer(buf_, buf_fill_, 1);
    buf_fill_ = buf_;
  }
}

StringGenericWriter::~StringGenericWriter() {
  FinalRecycle();
  if (unused_size_) {
    s_->resize(s_->size() - unused_size_);
  }
}

std::pair StringGenericWriter::RecycleBuffer(char* buf_begin, char* buf_end, int want_at_least) {
  unused_size_ -= buf_end - buf_begin;

  int deficit = want_at_least - unused_size_;
  size_t size = s_->size();
  if (deficit > 0) {
    size_t new_size = std::max(size + deficit, size * 2);
    s_->resize(new_size);
    unused_size_ += new_size - size;
    size = new_size;
  }

  char* ptr = const_cast(s_->data() + size - unused_size_);
  return {ptr, ptr + unused_size_};
}

namespace {

// We use this special storage for GetHeapProfile implementation,
// where we're unable to use regular memory allocation facilities, and
// where we must return free()-able chunk of memory.
struct ChunkedStorage {
  struct Chunk {
    Chunk* next;
    const int size;
    int used;
    char data[1];

    explicit Chunk(int size) : next(nullptr), size(size), used(0) {}
  };

  const ChunkedWriterConfig& config;
  Chunk* last_chunk{};

  explicit ChunkedStorage(const ChunkedWriterConfig& config) : config(config) {}

  ~ChunkedStorage() {
    RAW_DCHECK(last_chunk == nullptr, "storage must be released");
  }

  void CloseChunk(int actually_filled) {
    RAW_DCHECK(last_chunk->used == 0, "");
    last_chunk->used = actually_filled;
  }

  Chunk* AppendChunk(int want_at_least) {
    RAW_DCHECK(last_chunk == nullptr || last_chunk->used > 0, "");

    int size = std::max(want_at_least + sizeof(Chunk), config.buffer_size);

    constexpr auto kChunkSize = sizeof(Chunk) - 1;
    Chunk* chunk = new (config.chunk_malloc(size)) Chunk(size - kChunkSize);
    chunk->next = last_chunk;
    last_chunk = chunk;
    return chunk;
  }

  char* StrDupAndRelease() {
    size_t total_size = 0;

    // On first pass we calculate total size.
    Chunk* ptr = last_chunk;
    while (ptr) {
      total_size += ptr->used;
      ptr = ptr->next;
    }

    char* data = static_cast(malloc(total_size + 1));
    data[total_size] = 0;

    // Then we fill data backwards and free accumulated chunks.
    ptr = last_chunk;
    while (ptr) {
      memcpy(data + total_size - ptr->used, ptr->data, ptr->used);
      total_size -= ptr->used;
      Chunk* next = ptr->next;
      config.chunk_free(ptr);
      ptr = next;
    }
    last_chunk = nullptr;
    return data;
  }
};

class ChunkedStorageWriter : public GenericWriter {
public:
  explicit ChunkedStorageWriter(ChunkedStorage* storage) : storage_(storage) {}
  ~ChunkedStorageWriter() override {
    FinalRecycle();
  }
private:
  std::pair RecycleBuffer(char* buf_begin, char* buf_end, int want_at_least) override {
    if (storage_->last_chunk != nullptr) {
      storage_->CloseChunk(buf_end - buf_begin);
    }
    if (want_at_least == 0) {
      return {nullptr, 0};
    }
    auto* chunk = storage_->AppendChunk(want_at_least);
    return {chunk->data, chunk->data + chunk->size};
  }
  ChunkedStorage* const storage_;
};

}  // namespace

char* DoWithWriterToStrDup(const ChunkedWriterConfig& config, void (*body)(GenericWriter* writer, void* arg), void* arg) {
  ChunkedStorage storage(config);
  {
    ChunkedStorageWriter writer{&storage};
    body(&writer, arg);
    // Ensure writer is destroyed and releases it's entire output
    // into storage.
  }
  return storage.StrDupAndRelease();
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/base/generic_writer.h000066400000000000000000000147461513545575200227240ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef BASE_GENERIC_WRITER_H_
#define BASE_GENERIC_WRITER_H_
#include "config.h"

#include 
#include 

#include 
#include 

#include "base/basictypes.h"
#include "base/logging.h"

namespace tcmalloc {

// Generic Writer is abstract sink of usually text data. It can be
// printf-ed into.
class ATTRIBUTE_VISIBILITY_HIDDEN GenericWriter {
public:
#if defined(HAVE___ATTRIBUTE__)
  void AppendF(const char* fmt, ...) __attribute__ ((format(printf, 2, 3)));
#else
  void AppendF(const char* fmt, ...);
#endif

  void AppendMem(const char* str, size_t sz);
  void AppendStr(const char* str) {
    AppendMem(str, strlen(str));
  }

protected:
  virtual ~GenericWriter();

  virtual std::pair RecycleBuffer(char* buf_begin, char* buf_end, int want_at_least) = 0;

  // Must be called by child's destructor
  void FinalRecycle() {
    RecycleBuffer(buf_, buf_fill_, 0);
    buf_fill_ = buf_;
  }

private:
  char* buf_{};
  char* buf_fill_{};
  char* buf_end_{};
};

// WriteFnWriter is implementation of GenericWriter that writes via
// given abstract writer fn (i.e. could be lambda in practice). Note,
// this implementation is good for usage from inside guts of heap
// profiler and what not, under very strict locks. In particular it
// avoids any memory allocation by holding it's buffer within itself.
template 
class ATTRIBUTE_VISIBILITY_HIDDEN WriteFnWriter : public GenericWriter {
public:
  explicit WriteFnWriter(const WriteFn& write_fn) : write_fn_(write_fn) {}
  ~WriteFnWriter() override {
    FinalRecycle();
  }

private:
  std::pair RecycleBuffer(char* buf_begin, char* buf_end, int want_at_least) override {
    int actually_filled = buf_end - buf_begin;
    if (actually_filled > 0) {
      write_fn_(static_buffer_, actually_filled);
    }

    return {static_buffer_, static_buffer_ + kSize};
  }

  const WriteFn& write_fn_;
  char static_buffer_[kSize];
};

struct ATTRIBUTE_VISIBILITY_HIDDEN RawFDWriteFn {
  const RawFD fd;
  explicit RawFDWriteFn(RawFD fd) : fd(fd) {}
  void operator()(const char* buf, size_t amt) const {
    RawWrite(fd, buf, amt);
  }
};

// RawFDGenericWriter is implementation of GenericWriter that writes to
// given file descriptor. Note, this implementation is good for usage
// from inside guts of heap profiler and what not, under very strict
// locks. In particular it avoids any memory allocation by holding
// it's buffer within itself.
template 
class ATTRIBUTE_VISIBILITY_HIDDEN RawFDGenericWriter : private RawFDWriteFn, public WriteFnWriter {
public:
  explicit RawFDGenericWriter(RawFD fd) : RawFDWriteFn(fd), WriteFnWriter{*static_cast(this)} {}
  ~RawFDGenericWriter() override = default;
};

// StringGenericWriter is GenericWriter implementation that appends to
// given std::string instance.
class ATTRIBUTE_VISIBILITY_HIDDEN StringGenericWriter : public GenericWriter {
public:
  explicit StringGenericWriter(std::string* s) : s_(s) {}
  ~StringGenericWriter() override;

private:
  std::pair RecycleBuffer(char* buf_begin, char* buf_end, int want_at_least) override;

  std::string* s_;
  int unused_size_{}; // suffix of s_'s contents available to be filled
};

// ChunkedWriterConfig config is used by WithWriterToStrDup. See below
// for details. It is used to describe API to allocate memory for
// chunks holding data (Profiler{Malloc, Free} are used in practice).
struct ATTRIBUTE_VISIBILITY_HIDDEN ChunkedWriterConfig {
  typedef void* (*malloc_fn)(size_t);
  typedef void (*free_fn)(void*);

  malloc_fn chunk_malloc;
  free_fn chunk_free;
  int buffer_size;

  ChunkedWriterConfig(malloc_fn chunk_malloc, free_fn chunk_free, int buffer_size = 1 << 20)
    : chunk_malloc(chunk_malloc), chunk_free(chunk_free), buffer_size(buffer_size) {}
};

// Internal. Same as WithWriterToStrDup below.
ATTRIBUTE_VISIBILITY_HIDDEN
char* DoWithWriterToStrDup(const ChunkedWriterConfig& config, void (*body)(GenericWriter* writer, void* arg), void* arg);

// WithWriterToStrDup constructs GenericWriter instance that
// accumulates data in linked list of memory chunks allocated via
// means described in ChunkedWriterConfig. It passes that writer to
// given body (usually lambda) then after `body' is done with this
// writer, it's contents is converted into malloc-ed asciiz string.
//
// This unusual heap profiler's GetHeapProfile which processes profile
// under lock, so cannot allocate normally and which API and ABI
// returns malloc-ed asciiz string.
template 
char* WithWriterToStrDup(const ChunkedWriterConfig& config, const Body& body) {
  return DoWithWriterToStrDup(config, [] (GenericWriter* writer, void* arg) {
    const Body& body = *const_cast(static_cast(arg));
    body(writer);
  }, static_cast(const_cast(&body)));
}

}  // namespace tcmalloc

#endif  // BASE_GENERIC_WRITER_H_
gperftools-gperftools-2.18/src/base/googleinit.h000066400000000000000000000055721513545575200220510ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Jacob Hoffman-Andrews

#ifndef _GOOGLEINIT_H
#define _GOOGLEINIT_H

#include "base/logging.h"

class GoogleInitializer {
 public:
  typedef void (*VoidFunction)(void);
  GoogleInitializer(const char* name, VoidFunction ctor, VoidFunction dtor)
      : name_(name), destructor_(dtor) {
    RAW_VLOG(10, " constructing: %s\n", name_);
    if (ctor)
      ctor();
  }
  ~GoogleInitializer() {
    RAW_VLOG(10, " destroying: %s\n", name_);
    if (destructor_)
      destructor_();
  }

 private:
  const char* const name_;
  const VoidFunction destructor_;
};

#define REGISTER_MODULE_INITIALIZER(name, body)                 \
  namespace {                                                   \
    static void google_init_module_##name () { body; }          \
    GoogleInitializer google_initializer_module_##name(#name,   \
            google_init_module_##name, nullptr);                \
  }

#define REGISTER_MODULE_DESTRUCTOR(name, body)                  \
  namespace {                                                   \
    static void google_destruct_module_##name () { body; }      \
    GoogleInitializer google_destructor_module_##name(#name,    \
            nullptr, google_destruct_module_##name);            \
  }


#endif /* _GOOGLEINIT_H */
gperftools-gperftools-2.18/src/base/logging.cc000066400000000000000000000073261513545575200214740ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// This file just provides storage for FLAGS_verbose.

#include 
#include "base/logging.h"
#include "base/commandlineflags.h"

DEFINE_int32(verbose, EnvToInt("PERFTOOLS_VERBOSE", 0),
             "Set to numbers >0 for more verbose output, or <0 for less.  "
             "--verbose == -4 means we log fatal errors only.");


#if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__)

// While windows does have a POSIX-compatible API
// (_open/_write/_close), it acquires memory.  Using this lower-level
// windows API is the closest we can get to being "raw".
RawFD RawOpenForWriting(const char* filename) {
  // CreateFile allocates memory if file_name isn't absolute, so if
  // that ever becomes a problem then we ought to compute the absolute
  // path on its behalf (perhaps the ntdll/kernel function isn't aware
  // of the working directory?)
  RawFD fd = CreateFileA(filename, GENERIC_WRITE, 0, nullptr,
                         CREATE_ALWAYS, 0, nullptr);
  if (fd != kIllegalRawFD && GetLastError() == ERROR_ALREADY_EXISTS)
    SetEndOfFile(fd);    // truncate the existing file
  return fd;
}

void RawWrite(RawFD handle, const char* buf, size_t len) {
  while (len > 0) {
    DWORD wrote;
    BOOL ok = WriteFile(handle, buf, len, &wrote, nullptr);
    // We do not use an asynchronous file handle, so ok==false means an error
    if (!ok) break;
    buf += wrote;
    len -= wrote;
  }
}

void RawClose(RawFD handle) {
  CloseHandle(handle);
}

#else  // _WIN32 || __CYGWIN__ || __CYGWIN32__

#ifdef HAVE_SYS_TYPES_H
#include 
#endif
#ifdef HAVE_UNISTD_H
#include 
#endif
#ifdef HAVE_FCNTL_H
#include 
#endif

// Re-run fn until it doesn't cause EINTR.
#define NO_INTR(fn)  do {} while ((fn) < 0 && errno == EINTR)

RawFD RawOpenForWriting(const char* filename) {
  return open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0664);
}

void RawWrite(RawFD fd, const char* buf, size_t len) {
  while (len > 0) {
    ssize_t r;
    NO_INTR(r = write(fd, buf, len));
    if (r <= 0) break;
    buf += r;
    len -= r;
  }
}

void RawClose(RawFD fd) {
  close(fd);
}

#endif  // _WIN32 || __CYGWIN__ || __CYGWIN32__
gperftools-gperftools-2.18/src/base/logging.h000066400000000000000000000242531513545575200213340ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// This file contains #include information about logging-related stuff.
// Pretty much everybody needs to #include this file so that they can
// log various happenings.
//
#ifndef _LOGGING_H_
#define _LOGGING_H_

#include 
#include 
#include 
#include 
#ifdef HAVE_UNISTD_H
#include     // for write()
#endif
#include     // for strlen(), strcmp()
#include 
#include      // for errno
#include "base/commandlineflags.h"

// On some systems (like freebsd), we can't call write() at all in a
// global constructor, perhaps because errno hasn't been set up.
// (In windows, we can't call it because it might call malloc.)
// Calling the write syscall is safer (it doesn't set errno), so we
// prefer that.  Note we don't care about errno for logging: we just
// do logging on a best-effort basis.
#if defined(_MSC_VER)
#define WRITE_TO_STDERR(buf, len) WriteToStderr(buf, len);  // in port.cc
#elif HAVE_SYS_SYSCALL_H && !defined(__APPLE__)
#include 
#define WRITE_TO_STDERR(buf, len) syscall(SYS_write, STDERR_FILENO, buf, len)
#else
#define WRITE_TO_STDERR(buf, len) write(STDERR_FILENO, buf, len)
#endif

// We log all messages at this log-level and below.
// INFO == -1, WARNING == -2, ERROR == -3, FATAL == -4
DECLARE_int32(verbose);

// CHECK dies with a fatal error if condition is not true.  It is *not*
// controlled by NDEBUG, so the check will be executed regardless of
// compilation mode.  Therefore, it is safe to do things like:
//    CHECK(fp->Write(x) == 4)
// Note we use write instead of printf/puts to avoid the risk we'll
// call malloc().
#define CHECK(condition)                                                \
  do {                                                                  \
    if (!(condition)) {                                                 \
      WRITE_TO_STDERR("Check failed: " #condition "\n",                 \
                      sizeof("Check failed: " #condition "\n")-1);      \
      abort();                                                          \
    }                                                                   \
  } while (0)

// This takes a message to print.  The name is historical.
#define RAW_CHECK(condition, message)                                          \
  do {                                                                         \
    if (!(condition)) {                                                        \
      WRITE_TO_STDERR("Check failed: " #condition ": " message "\n",           \
                      sizeof("Check failed: " #condition ": " message "\n")-1);\
      abort();                                                                 \
    }                                                                          \
  } while (0)

// This is like RAW_CHECK, but only in debug-mode
#ifdef NDEBUG
#define RAW_DCHECK(condition, message)
#else
#define RAW_DCHECK(condition, message)  RAW_CHECK(condition, message)
#endif

// This prints errno as well.  Note we use write instead of printf/puts to
// avoid the risk we'll call malloc().
#define PCHECK(condition)                                               \
  do {                                                                  \
    if (!(condition)) {                                                 \
      const int err_no = errno;                                         \
      WRITE_TO_STDERR("Check failed: " #condition ": ",                 \
                      sizeof("Check failed: " #condition ": ")-1);      \
      WRITE_TO_STDERR(strerror(err_no), strlen(strerror(err_no)));      \
      WRITE_TO_STDERR("\n", sizeof("\n")-1);                            \
      abort();                                                          \
    }                                                                   \
  } while (0)

// Helper macro for binary operators; prints the two values on error
// Don't use this macro directly in your code, use CHECK_EQ et al below

// WARNING: These don't compile correctly if one of the arguments is a
// pointer and the other is nullptr. To work around this, simply
// static_cast nullptr to the type of the desired pointer.

// TODO(jandrews): Also print the values in case of failure.  Requires some
// sort of type-sensitive ToString() function.
#define CHECK_OP(op, val1, val2)                                        \
  do {                                                                  \
    if (!((val1) op (val2))) {                                          \
      fprintf(stderr, "%s:%d Check failed: %s %s %s\n", __FILE__, __LINE__, #val1, #op, #val2); \
      abort();                                                          \
    }                                                                   \
  } while (0)

#define CHECK_EQ(val1, val2) CHECK_OP(==, val1, val2)
#define CHECK_NE(val1, val2) CHECK_OP(!=, val1, val2)
#define CHECK_LE(val1, val2) CHECK_OP(<=, val1, val2)
#define CHECK_LT(val1, val2) CHECK_OP(< , val1, val2)
#define CHECK_GE(val1, val2) CHECK_OP(>=, val1, val2)
#define CHECK_GT(val1, val2) CHECK_OP(> , val1, val2)

// Used for (libc) functions that return -1 and set errno
#define CHECK_ERR(invocation)  PCHECK((invocation) != -1)

// A few more checks that only happen in debug mode
#ifdef NDEBUG
#define DCHECK_EQ(val1, val2)
#define DCHECK_NE(val1, val2)
#define DCHECK_LE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2)
#else
#define DCHECK_EQ(val1, val2)  CHECK_EQ(val1, val2)
#define DCHECK_NE(val1, val2)  CHECK_NE(val1, val2)
#define DCHECK_LE(val1, val2)  CHECK_LE(val1, val2)
#define DCHECK_LT(val1, val2)  CHECK_LT(val1, val2)
#define DCHECK_GE(val1, val2)  CHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2)  CHECK_GT(val1, val2)
#endif


#ifdef ERROR
#undef ERROR      // may conflict with ERROR macro on windows
#endif
enum LogSeverity {INFO = -1, WARNING = -2, ERROR = -3, FATAL = -4};

// NOTE: we add a newline to the end of the output if it's not there already
inline void LogPrintf(int severity, const char* pat, va_list ap) {
  // We write directly to the stderr file descriptor and avoid FILE
  // buffering because that may invoke malloc()
  char buf[600];
  vsnprintf(buf, sizeof(buf)-1, pat, ap);
  if (buf[0] != '\0' && buf[strlen(buf)-1] != '\n') {
    assert(strlen(buf)+1 < sizeof(buf));
    strcat(buf, "\n");
  }
  WRITE_TO_STDERR(buf, strlen(buf));
  if ((severity) == FATAL)
    abort(); // LOG(FATAL) indicates a big problem, so don't run atexit() calls
}

// Note that since the order of global constructors is unspecified,
// global code that calls RAW_LOG may execute before FLAGS_verbose is set.
// Such code will run with verbosity == 0 no matter what.
#define VLOG_IS_ON(severity) (FLAGS_verbose >= severity)

// In a better world, we'd use __VA_ARGS__, but VC++ 7 doesn't support it.
#define LOG_PRINTF(severity, pat) do {          \
  if (VLOG_IS_ON(severity)) {                   \
    va_list ap;                                 \
    va_start(ap, pat);                          \
    LogPrintf(severity, pat, ap);               \
    va_end(ap);                                 \
  }                                             \
} while (0)

// RAW_LOG is the main function; some synonyms are used in unittests.
inline void RAW_LOG(int lvl, const char* pat, ...)  { LOG_PRINTF(lvl, pat); }
inline void RAW_VLOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat); }
inline void LOG(int lvl, const char* pat, ...)      { LOG_PRINTF(lvl, pat); }
inline void VLOG(int lvl, const char* pat, ...)     { LOG_PRINTF(lvl, pat); }
inline void LOG_IF(int lvl, bool cond, const char* pat, ...) {
  if (cond)  LOG_PRINTF(lvl, pat);
}

// This isn't technically logging, but it's also IO and also is an
// attempt to be "raw" -- that is, to not use any higher-level libc
// routines that might allocate memory or (ideally) try to allocate
// locks.  We use an opaque file handle (not necessarily an int)
// to allow even more low-level stuff in the future.
// Like other "raw" routines, these functions are best effort, and
// thus don't return error codes (except RawOpenForWriting()).
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__)
#ifndef NOMINMAX
#define NOMINMAX     // @#!$& windows
#endif
#include 
typedef HANDLE RawFD;
const RawFD kIllegalRawFD = INVALID_HANDLE_VALUE;
#else
typedef int RawFD;
const RawFD kIllegalRawFD = -1;   // what open returns if it fails
#endif  // defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__)

RawFD RawOpenForWriting(const char* filename);   // uses default permissions
void RawWrite(RawFD fd, const char* buf, size_t len);
void RawClose(RawFD fd);

#endif // _LOGGING_H_
gperftools-gperftools-2.18/src/base/low_level_alloc.cc000066400000000000000000000450611513545575200232060ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2006, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// A low-level allocator that can be used by other low-level
// modules without introducing dependency cycles.
// This allocator is slow and wasteful of memory;
// it should not be used when performance is key.
#include "config.h"

#include "base/low_level_alloc.h"

#include 

#include "base/logging.h"
#include "base/memmap.h"
#include "base/spinlock.h"
#include "base/static_storage.h"

// A first-fit allocator with amortized logarithmic free() time.

namespace tcmalloc {

LowLevelAlloc::PagesAllocator::~PagesAllocator() {
}

// ---------------------------------------------------------------------------
static constexpr int kMaxLevel = 30;
static constexpr size_t kMinimalRegion = 1 << 20;

// This struct describes one allocated block, or one free block.
struct AllocList {
  constexpr AllocList() {}

  struct Header {
    intptr_t size;  // size of entire region, including this field. Must be
    // first.  Valid in both allocated and unallocated blocks
    intptr_t magic; // kMagicAllocated or kMagicUnallocated xor this
    LowLevelAlloc::Arena *arena; // pointer to parent arena
    void *dummy_for_alignment;   // aligns regions to 0 mod 2*sizeof(void*)
  } header{};

  // Next two fields: in unallocated blocks: freelist skiplist data
  //                  in allocated blocks: overlaps with client data

  // levels in skiplist used
  int levels{};
  // actually has levels elements.  The AllocList node may not have
  // room for all kMaxLevel entries.  See max_fit in
  // LLA_SkiplistLevels()
  AllocList *next[kMaxLevel]{};
};

class DefaultPagesAllocator : public LowLevelAlloc::PagesAllocator {
public:
  virtual ~DefaultPagesAllocator() {};
  std::pair MapPages(size_t size) override;
  void UnMapPages(void *addr, size_t size) override;
};

// ---------------------------------------------------------------------------
// A trivial skiplist implementation.  This is used to keep the freelist
// in address order while taking only logarithmic time per insert and delete.

// An integer approximation of log2(size/base)
// Requires size >= base.
static int IntLog2(size_t size, size_t base) {
  int result = 0;
  for (size_t i = size; i > base; i >>= 1) { // i == floor(size/2**result)
    result++;
  }
  //    floor(size / 2**result) <= base < floor(size / 2**(result-1))
  // =>     log2(size/(base+1)) <= result < 1+log2(size/base)
  // => result ~= log2(size/base)
  return result;
}

// Return a random integer n:  p(n)=1/(2**n) if 1 <= n; p(n)=0 if n < 1.
static int Random() {
  static uint32_t r = 1;         // no locking---it's not critical
  int result = 1;
  while ((((r = r*1103515245 + 12345) >> 30) & 1) == 0) {
    result++;
  }
  return result;
}

// Return a number of skiplist levels for a node of size bytes, where
// base is the minimum node size.  Compute level=log2(size / base)+n
// where n is 1 if random is false and otherwise a random number generated with
// the standard distribution for a skiplist:  See Random() above.
// Bigger nodes tend to have more skiplist levels due to the log2(size / base)
// term, so first-fit searches touch fewer nodes.  "level" is clipped so
// level max_fit)     level = max_fit;
  if (level > kMaxLevel-1) level = kMaxLevel - 1;
  RAW_CHECK(level >= 1, "block not big enough for even one level");
  return level;
}

// Return "atleast", the first element of AllocList *head s.t. *atleast >= *e.
// For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater
// points to the last element at level i in the AllocList less than *e, or is
// head if no such element exists.
static AllocList *LLA_SkiplistSearch(AllocList *head,
                                     AllocList *e, AllocList **prev) {
  AllocList *p = head;
  for (int level = head->levels - 1; level >= 0; level--) {
    for (AllocList *n; (n = p->next[level]) != 0 && n < e; p = n) {
    }
    prev[level] = p;
  }
  return (head->levels == 0) ?  0 : prev[0]->next[0];
}

// Insert element *e into AllocList *head.  Set prev[] as LLA_SkiplistSearch.
// Requires that e->levels be previously set by the caller (using
// LLA_SkiplistLevels())
static void LLA_SkiplistInsert(AllocList *head, AllocList *e,
                               AllocList **prev) {
  LLA_SkiplistSearch(head, e, prev);
  for (; head->levels < e->levels; head->levels++) { // extend prev pointers
    prev[head->levels] = head;                       // to all *e's levels
  }
  for (int i = 0; i != e->levels; i++) { // add element to list
    e->next[i] = prev[i]->next[i];
    prev[i]->next[i] = e;
  }
}

// Remove element *e from AllocList *head.  Set prev[] as LLA_SkiplistSearch().
// Requires that e->levels be previous set by the caller (using
// LLA_SkiplistLevels())
static void LLA_SkiplistDelete(AllocList *head, AllocList *e,
                               AllocList **prev) {
  AllocList *found = LLA_SkiplistSearch(head, e, prev);
  RAW_CHECK(e == found, "element not in freelist");
  for (int i = 0; i != e->levels && prev[i]->next[i] == e; i++) {
    prev[i]->next[i] = e->next[i];
  }
  while (head->levels > 0 && head->next[head->levels - 1] == 0) {
    head->levels--;   // reduce head->levels if level unused
  }
}

// ---------------------------------------------------------------------------
// Arena implementation

struct LowLevelAlloc::Arena {
  Arena();

  SpinLock mu;                // protects freelist, allocation_count,
                              // roundup, min_size

  AllocList freelist;         // head of free list; sorted by addr (under mu)
  int32_t allocation_count;   // count of allocated blocks (under mu)
  size_t roundup;             // lowest power of 2 >= max(16,sizeof (AllocList))
                              // (init under mu, then ro)
  size_t min_size;            // smallest allocation block size
                              // (init under mu, then ro)
  PagesAllocator *allocator;

  void InsertAllocatedMemoryLocked(void *new_pages, size_t new_pages_size);
};

// magic numbers to identify allocated and unallocated blocks
static const intptr_t kMagicAllocated = 0x4c833e95;
static const intptr_t kMagicUnallocated = ~kMagicAllocated;

// create an appropriate magic number for an object at "ptr"
// "magic" should be kMagicAllocated or kMagicUnallocated
static intptr_t Magic(intptr_t magic, AllocList::Header *ptr) {
  return magic ^ reinterpret_cast(ptr);
}

LowLevelAlloc::Arena::Arena() {
  // Round up block sizes to a power of two close to the header size.
  roundup = 16;
  while (roundup < sizeof (freelist.header)) {
    roundup += roundup;
  }
  // Don't allocate blocks less than twice the roundup size to avoid tiny
  // free blocks.
  min_size = 2 * roundup;
  freelist.header.size = 0;
  freelist.header.magic =
    Magic(kMagicUnallocated, &freelist.header);
  freelist.header.arena = this;
  freelist.levels = 0;
  memset(freelist.next, 0, sizeof (freelist.next));
  allocation_count = 0;
  allocator = LowLevelAlloc::GetDefaultPagesAllocator();
}

LowLevelAlloc::Arena *LowLevelAlloc::NewArena() {
  return NewArenaWithCustomAlloc(nullptr);
}

LowLevelAlloc::Arena *LowLevelAlloc::NewArenaWithCustomAlloc(PagesAllocator *allocator) {
  if (allocator) {
    void* memory;
    size_t got_amount;
    std::tie(memory, got_amount) = allocator->MapPages(kMinimalRegion);

    Arena *result = new (memory) Arena();
    result->allocator = allocator;
    result->mu.Lock();
    result->InsertAllocatedMemoryLocked(result + 1, got_amount - sizeof(Arena));
    result->mu.Unlock();
    return result;
  }

  return new (AllocWithArena(sizeof(Arena), nullptr)) Arena();
}

// L < arena->mu, L < arena->arena->mu
bool LowLevelAlloc::DeleteArena(Arena *arena) {
  {
    SpinLockHolder locker{&arena->mu};
    bool empty = (arena->allocation_count == 0);
    DCHECK_EQ(empty, true);
    if (!empty) {
      return empty;
    }
  }

  AllocList* first_region = reinterpret_cast(arena + 1);
  bool seen_first_region = false;
  while (arena->freelist.next[0] != 0) {
    AllocList *region = arena->freelist.next[0];
    if (region == first_region) {
      RAW_CHECK(!seen_first_region, "");
      seen_first_region = true;
      arena->freelist.next[0] = region->next[0];
      continue;
    }

    size_t size = region->header.size;
    arena->freelist.next[0] = region->next[0];
    RAW_CHECK(region->header.magic ==
              Magic(kMagicUnallocated, ®ion->header),
              "bad magic number in DeleteArena()");
    RAW_CHECK(region->header.arena == arena,
              "bad arena pointer in DeleteArena()");
    arena->allocator->UnMapPages(region, size);
  }

  if (auto allocator = arena->allocator; allocator != GetDefaultPagesAllocator()) {
    RAW_CHECK(seen_first_region, "");
    size_t size = first_region->header.size;
    allocator->UnMapPages(reinterpret_cast(first_region) - 1, size + sizeof(Arena));
  } else {
    RAW_CHECK(!seen_first_region, "");
    Free(arena);
  }

  return true; // empty
}

// ---------------------------------------------------------------------------

// Return value rounded up to next multiple of align.
// align must be a power of two.
static intptr_t RoundUp(intptr_t addr, intptr_t align) {
  return (addr + align - 1) & ~(align - 1);
}

// Equivalent to "return prev->next[i]" but with sanity checking
// that the freelist is in the correct order, that it
// consists of regions marked "unallocated", and that no two regions
// are adjacent in memory (they should have been coalesced).
// L < arena->mu
static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) {
  RAW_CHECK(i < prev->levels, "too few levels in Next()");
  AllocList *next = prev->next[i];
  if (next != 0) {
    RAW_CHECK(next->header.magic == Magic(kMagicUnallocated, &next->header),
              "bad magic number in Next()");
    RAW_CHECK(next->header.arena == arena,
              "bad arena pointer in Next()");
    if (prev != &arena->freelist) {
      RAW_CHECK(prev < next, "unordered freelist");
      RAW_CHECK(reinterpret_cast(prev) + prev->header.size <
                reinterpret_cast(next), "malformed freelist");
    }
  }
  return next;
}

// Coalesce list item "a" with its successor if they are adjacent.
static void Coalesce(AllocList *a) {
  AllocList *n = a->next[0];
  if (n != 0 && reinterpret_cast(a) + a->header.size ==
                    reinterpret_cast(n)) {
    LowLevelAlloc::Arena *arena = a->header.arena;
    a->header.size += n->header.size;
    n->header.magic = 0;
    n->header.arena = 0;
    AllocList *prev[kMaxLevel];
    LLA_SkiplistDelete(&arena->freelist, n, prev);
    LLA_SkiplistDelete(&arena->freelist, a, prev);
    a->levels = LLA_SkiplistLevels(a->header.size, arena->min_size, true);
    LLA_SkiplistInsert(&arena->freelist, a, prev);
  }
}

// Adds block at location "v" to the free list
// L >= arena->mu
static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) {
  AllocList *f = reinterpret_cast(
                        reinterpret_cast(v) - sizeof (f->header));
  RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
            "bad magic number in AddToFreelist()");
  RAW_CHECK(f->header.arena == arena,
            "bad arena pointer in AddToFreelist()");
  f->levels = LLA_SkiplistLevels(f->header.size, arena->min_size, true);
  AllocList *prev[kMaxLevel];
  LLA_SkiplistInsert(&arena->freelist, f, prev);
  f->header.magic = Magic(kMagicUnallocated, &f->header);
  Coalesce(f);                  // maybe coalesce with successor
  Coalesce(prev[0]);            // maybe coalesce with predecessor
}

// Frees storage allocated by LowLevelAlloc::Alloc().
// L < arena->mu
void LowLevelAlloc::Free(void *v) {
  if (!v) {
    return;
  }
  AllocList *f = reinterpret_cast(
    reinterpret_cast(v) - sizeof (f->header));
  RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
            "bad magic number in Free()");
  LowLevelAlloc::Arena *arena = f->header.arena;

  SpinLockHolder locker{&arena->mu};

  AddToFreelist(v, arena);
  RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free");
  arena->allocation_count--;
}

size_t LowLevelAlloc::UsableSize(const void *p) {
  const AllocList *f = reinterpret_cast(
                        reinterpret_cast(p) - sizeof (f->header));
  return f->header.size - sizeof(f->header);
}

void *LowLevelAlloc::Alloc(size_t request) {
  return AllocWithArena(request, nullptr);
}

void LowLevelAlloc::Arena::InsertAllocatedMemoryLocked(void *new_pages, size_t new_pages_size) {
  AllocList *s;
  s = reinterpret_cast(new_pages);
  s->header.size = new_pages_size;
  // Pretend the block is allocated; call AddToFreelist() to free it.
  s->header.magic = Magic(kMagicAllocated, &s->header);
  s->header.arena = this;
  AddToFreelist(&s->levels, this);  // insert new region into free
}

// allocates and returns a block of size bytes, to be freed with Free()
// L < arena->mu
void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
  if (!request) {
    return nullptr;
  }

  if (!arena) {
    arena = DefaultArena();
  }

  AllocList *s;       // will point to region that satisfies request
  SpinLockHolder locker{&arena->mu};

  // round up with header
  size_t req_rnd = RoundUp(request + sizeof (s->header), arena->roundup);
  for (;;) {      // loop until we find a suitable region
    // find the minimum levels that a block of this size must have
    int i = LLA_SkiplistLevels(req_rnd, arena->min_size, false) - 1;
    if (i < arena->freelist.levels) {   // potential blocks exist
      AllocList *before = &arena->freelist;  // predecessor of s
      while ((s = Next(i, before, arena)) != 0 && s->header.size < req_rnd) {
        before = s;
      }
      if (s != 0) {       // we found a region
        break;
      }
    }
    // we unlock before mmap() both because mmap() may call a callback hook,
    // and because it may be slow.
    arena->mu.Unlock();

    size_t new_pages_size = RoundUp(req_rnd, kMinimalRegion);
    void *new_pages;
    std::tie(new_pages, new_pages_size) = arena->allocator->MapPages(new_pages_size);

    arena->mu.Lock();
    arena->InsertAllocatedMemoryLocked(new_pages, new_pages_size);
  }
  AllocList *prev[kMaxLevel];
  LLA_SkiplistDelete(&arena->freelist, s, prev);    // remove from free list
  // s points to the first free region that's big enough
  if (req_rnd + arena->min_size <= s->header.size) {  // big enough to split
    AllocList *n = reinterpret_cast
      (req_rnd + reinterpret_cast(s));
    n->header.size = s->header.size - req_rnd;
    n->header.magic = Magic(kMagicAllocated, &n->header);
    n->header.arena = arena;
    s->header.size = req_rnd;
    AddToFreelist(&n->levels, arena);
  }
  s->header.magic = Magic(kMagicAllocated, &s->header);
  RAW_CHECK(s->header.arena == arena, "");
  arena->allocation_count++;

  return &s->levels;
}

static tcmalloc::StaticStorage default_arena_storage;

LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() {
  static Arena* arena;
  if (!arena) {
    // Note, we expect this to happen early enough in process
    // lifetime, so we can afford to do without memory barriers.
    arena = default_arena_storage.Construct();
  }
  return arena;
}

static tcmalloc::StaticStorage default_pages_allocator;

LowLevelAlloc::PagesAllocator *LowLevelAlloc::GetDefaultPagesAllocator(void) {
  static tcmalloc::TrivialOnce once;
  once.RunOnce(+[] () {
    default_pages_allocator.Construct();
  });
  return default_pages_allocator.get();
}

static size_t cached_pagesize() {
  static size_t pagesize;
  if (!pagesize) {
    pagesize = getpagesize();
  }
  return pagesize;
}

std::pair DefaultPagesAllocator::MapPages(size_t size) {
  // roundup size
  size_t actual_size = size;
  size_t pagesize = cached_pagesize();
  actual_size += (~actual_size + 1) & (pagesize - 1);
  if (actual_size < size) {
    // overflow. We'll get MapAnonymous below fail with large enough
    // request.
    actual_size = size;
  }

  auto result = tcmalloc::MapAnonymous(actual_size);

  RAW_CHECK(result.success, "mmap error");

  return {result.addr, actual_size};
}

void DefaultPagesAllocator::UnMapPages(void *region, size_t size) {
  size_t pagesize = cached_pagesize();
  (void)pagesize;

  RAW_CHECK(reinterpret_cast(region) % pagesize == 0,
            "empty arena has non-page-aligned block");
  RAW_CHECK(size % pagesize == 0,
            "empty arena has non-page-aligned size");

  int munmap_result = munmap(region, size);
  RAW_CHECK(munmap_result == 0,
            "LowLevelAlloc::DeleteArena: munmap failed address");
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/base/low_level_alloc.h000066400000000000000000000075701513545575200230530ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2006, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#if !defined(_BASE_LOW_LEVEL_ALLOC_H_)
#define _BASE_LOW_LEVEL_ALLOC_H_

// A simple thread-safe memory allocator that does not depend on
// mutexes or thread-specific data.  It is intended to be used
// sparingly, and only when malloc() would introduce an unwanted
// dependency, such as inside the heap-checker.

#include "config.h"

#include 

#include 

namespace tcmalloc {

class LowLevelAlloc {
 public:
  class PagesAllocator {
  public:
    virtual ~PagesAllocator();
    virtual std::pair MapPages(size_t size) = 0;
    virtual void UnMapPages(void *addr, size_t size) = 0;
  };

  struct Arena;       // an arena from which memory may be allocated

  // Returns a pointer to a block of at least "request" bytes
  // that have been newly allocated from the specific arena.
  // for Alloc() call the DefaultArena() is used.
  // Returns 0 if passed request==0.
  // Does not return 0 under other circumstances; it crashes if memory
  // is not available.
  //
  // Passing nullptr arena implies use of DefaultArena
  static void *AllocWithArena(size_t request, Arena *arena);
  // Equivalent to AllocWithArena(request, nullptr)
  static void *Alloc(size_t request);

  static size_t UsableSize(const void *p);

  // Deallocates a region of memory that was previously allocated with
  // Alloc().   Does nothing if passed 0.   "s" must be either 0,
  // or must have been returned from a call to Alloc() and not yet passed to
  // Free() since that call to Alloc().  The space is returned to the arena
  // from which it was allocated.
  static void Free(void *s);

  static Arena *NewArena();

  // note: pages allocator will never be destroyed and allocated pages will never be freed
  // When allocator is nullptr, it's same as NewArena
  static Arena *NewArenaWithCustomAlloc(PagesAllocator *allocator);

  // Destroys an arena allocated by NewArena and returns true,
  // provided no allocated blocks remain in the arena.
  // If allocated blocks remain in the arena, does nothing and
  // returns false.
  // It is illegal to attempt to destroy the DefaultArena().
  static bool DeleteArena(Arena *arena);

  static PagesAllocator *GetDefaultPagesAllocator(void);

private:
  static Arena *DefaultArena();

  LowLevelAlloc();      // no instances
};

}  // namespace tcmalloc

#endif
gperftools-gperftools-2.18/src/base/memmap.h000066400000000000000000000050671513545575200211640ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef MEMMAP_H_
#define MEMMAP_H_

#include "config.h"

#ifdef _WIN32
// Windows has mmap bits defined in it's port.h header
#else
// Everything we assume is sufficiently POSIX-compatible. Also we
// assume ~everyone has MAP_ANONYMOUS or similar (POSIX, strangely,
// doesn't!)
#include 
#include 

// Someone still cares about those near-obsolete OSes that fail to
// supply MAP_ANONYMOUS.
# ifndef MAP_ANONYMOUS
#  define MAP_ANONYMOUS MAP_ANON
# endif

#endif

namespace tcmalloc {

struct MMapResult {
  void* addr;
  bool success;
};

// MapAnonymous does mmap of r+w anonymous memory, simply saving us
// some hassle of spreading (not 100% portable) flags.
static inline MMapResult MapAnonymous(size_t length) {
  MMapResult result;
  result.addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
  result.success = (result.addr != MAP_FAILED);
  return result;
}

}  // namespace tcmalloc

#endif  // MEMMAP_H_
gperftools-gperftools-2.18/src/base/proc_maps_iterator.cc000066400000000000000000000460641513545575200237440ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config.h"

#include "base/proc_maps_iterator.h"

#include     // for isspace()
#include    // for getenv()
#include     // IWYU pragma: keep
#include    // for memmove(), memchr(), etc.
#include     // for open()
#include     // for errno
#include    // for PATH_MAX

#ifdef HAVE_UNISTD_H
#include    // for read()
#endif

#if (defined(_WIN32) || defined(__MINGW32__)) && !defined(__CYGWIN__) && !defined(__CYGWIN32)
# define PLATFORM_WINDOWS 1
#endif

#if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__))
#include    // for DWORD etc
#include          // for Module32First()
#endif

#if defined __MACH__          // Mac OS X, almost certainly
#include       // for iterating over dll's in ProcMapsIter
#include     // for iterating over dll's in ProcMapsIter
#include 
#include        // how we figure out numcpu's on OS X
#elif defined __FreeBSD__
#include 
#elif defined __sun__         // Solaris
#include            // for, e.g., prmap_t
#elif defined(PLATFORM_WINDOWS)
#include           // for getpid() (actually, _getpid())
#include           // for SHGetValueA()
#include          // for Module32First()
#elif defined(__QNXNTO__)
#include 
#include 
#endif

#if __FreeBSD__ && !defined TCMALLOC_WANT_DL_ITERATE_PHDR
#define TCMALLOC_WANT_DL_ITERATE_PHDR
#endif

#if defined TCMALLOC_WANT_DL_ITERATE_PHDR
#include 
#endif

#include 

#include "base/function_ref.h"
#include "base/logging.h"
#include "base/sysinfo.h"

#include "base/for_each_line.h"

#ifdef PLATFORM_WINDOWS
#ifdef MODULEENTRY32
// In a change from the usual W-A pattern, there is no A variant of
// MODULEENTRY32.  Tlhelp32.h #defines the W variant, but not the A.
// In unicode mode, tlhelp32.h #defines MODULEENTRY32 to be
// MODULEENTRY32W.  These #undefs are the only way I see to get back
// access to the original, ascii struct (and related functions).
#undef MODULEENTRY32
#undef Module32First
#undef Module32Next
#undef PMODULEENTRY32
#undef LPMODULEENTRY32
#endif  /* MODULEENTRY32 */
// MinGW doesn't seem to define this, perhaps some windowsen don't either.
#ifndef TH32CS_SNAPMODULE32
#define TH32CS_SNAPMODULE32  0
#endif  /* TH32CS_SNAPMODULE32 */
#endif  /* PLATFORM_WINDOWS */

// Re-run fn until it doesn't cause EINTR.
#define NO_INTR(fn)  do {} while ((fn) < 0 && errno == EINTR)

namespace tcmalloc {

namespace {

template 
bool DoForEachLine(const char* path, const Body& body) {
  int fd;
  NO_INTR(fd = open(path, O_RDONLY));
  if (fd < 0) {
    return false;
  }

  auto reader = [fd] (void* buf, int sz) -> int {
    int nread;
    NO_INTR(nread = read(fd, buf, sz));
    return nread;
  };

  bool ok = ForEachLine<1024>(reader, body);

  (void)close(fd);
  return ok;
}

// Finds |c| in |text|, and assign '\0' at the found position.
// The original character at the modified position should be |c|.
// A pointer to the modified position is stored in |endptr|.
// |endptr| should not be nullptr.
bool ExtractUntilChar(char *text, int c, char **endptr) {
  CHECK_NE(text, nullptr);
  CHECK_NE(endptr, nullptr);
  char *found;
  found = strchr(text, c);
  if (found == nullptr) {
    *endptr = nullptr;
    return false;
  }

  *endptr = found;
  *found = '\0';
  return true;
}

// Increments |*text_pointer| while it points a whitespace character.
// It is to follow sscanf's whilespace handling.
void SkipWhileWhitespace(char **text_pointer, int c) {
  if (isspace(c)) {
    while (isspace(**text_pointer) && isspace(*((*text_pointer) + 1))) {
      ++(*text_pointer);
    }
  }
}

uint64_t StringToIntegerUntilChar(
    char *text, int base, int c, char **endptr_result) {
  CHECK_NE(endptr_result, nullptr);
  *endptr_result = nullptr;

  char *endptr_extract;
  if (!ExtractUntilChar(text, c, &endptr_extract))
    return 0;

  uint64_t result;
  char *endptr_strto;
  result = strtoull(text, &endptr_strto, base);
  *endptr_extract = c;

  if (endptr_extract != endptr_strto)
    return 0;

  *endptr_result = endptr_extract;
  SkipWhileWhitespace(endptr_result, c);

  return result;
}

char *CopyStringUntilChar(
    char *text, unsigned out_len, int c, char *out) {
  char *endptr;
  if (!ExtractUntilChar(text, c, &endptr))
    return nullptr;

  strncpy(out, text, out_len);
  out[out_len-1] = '\0';
  *endptr = c;

  SkipWhileWhitespace(&endptr, c);
  return endptr;
}

bool StringToIntegerUntilCharWithCheck(
    uint64_t *outptr, char *text, int base, int c, char **endptr) {
  *outptr = StringToIntegerUntilChar(*endptr, base, c, endptr);
  if (*endptr == nullptr || **endptr == '\0') return false;
  ++(*endptr);
  return true;
}

#if defined(__linux__) || defined(__NetBSD__)
bool ParseProcMapsLine(char *text, uint64_t *start, uint64_t *end,
                       char *flags, uint64_t *offset,
                       uint64_t *inode,
                       unsigned *filename_offset) {
  /*
   * It's similar to:
   * sscanf(text, "%"SCNx64"-%"SCNx64" %4s %"SCNx64" %x:%x %"SCNd64" %n",
   *        start, end, flags, offset, major, minor, inode, filename_offset)
   */
  char *endptr = text;
  if (endptr == nullptr || *endptr == '\0')  return false;

  if (!StringToIntegerUntilCharWithCheck(start, endptr, 16, '-', &endptr))
    return false;

  if (!StringToIntegerUntilCharWithCheck(end, endptr, 16, ' ', &endptr))
    return false;

  endptr = CopyStringUntilChar(endptr, 5, ' ', flags);
  if (endptr == nullptr || *endptr == '\0')  return false;
  ++endptr;

  if (!StringToIntegerUntilCharWithCheck(offset, endptr, 16, ' ', &endptr))
    return false;

  uint64_t dummy;
  if (!StringToIntegerUntilCharWithCheck(&dummy, endptr, 16, ':', &endptr))
    return false;

  if (!StringToIntegerUntilCharWithCheck(&dummy, endptr, 16, ' ', &endptr))
    return false;

  if (!StringToIntegerUntilCharWithCheck(inode, endptr, 10, ' ', &endptr))
    return false;

  *filename_offset = (endptr - text);
  return true;
}

bool DoIterateLinux(const char* path, void (*body)(const ProcMapping& mapping, void* arg), void* arg) {
  return DoForEachLine(
    path,
    [&] (char* line_start, char* line_end) {
      unsigned filename_offset;
      char flags_tmp[10];

      ProcMapping mapping;
      if (!ParseProcMapsLine(line_start,
                             &mapping.start, &mapping.end,
                             flags_tmp,
                             &mapping.offset, &mapping.inode,
                             &filename_offset)) {
        return false;
      }

      mapping.filename = line_start + filename_offset;
      mapping.flags = flags_tmp;
      body(mapping, arg);
      return true;
    });
}
#endif  // __linux__ || __NetBSD__

#if defined(__QNXNTO__)
bool DoIterateQNX(void (*body)(const ProcMapping& mapping, void* arg), void* arg) {
  return DoForEachLine(
    "/proc/self/pmap",
    [&] (char* line_start, char* line_end) {
      ProcMapping mapping;
      unsigned filename_offset;

      uint64_t q_vaddr, q_size, q_ino, q_offset;
      uint32_t q_flags, q_dev, q_prot;

      // pmap file start with below header info, skip it.
      // vaddr,size,flags,prot,maxprot,dev,ino,offset,rsv,guardsize,refcnt,mapcnt,path
      if (!strncmp(line_start, "vaddr,size,", 11)) {
          return true;
      }

      if (sscanf(line_start,
                 "0x%" SCNx64 ",0x%" SCNx64 ",0x%" SCNx32        \
                 ",0x%" SCNx32 ",0x%*x,0x%" SCNx32 ",0x%" SCNx64 \
                 ",0x%" SCNx64 ",0x%*x,0x%*x,0x%*x,0x%*x,%n",
                 &q_vaddr,
                 &q_size,
                 &q_flags,
                 &q_prot,
                 &q_dev,
                 &q_ino,
                 &q_offset,
                 &filename_offset) != 7) {
        return false;
      }

      mapping.start = q_vaddr;
      mapping.end = q_vaddr + q_size;
      mapping.offset = q_offset;
      mapping.inode = q_ino;
      // right shifted by 8 bits, restore it
      q_prot <<= 8;

      char flags_tmp[5] = {
        q_prot & PROT_READ ? 'r' : '-',
        q_prot & PROT_WRITE ? 'w' : '-',
        q_prot & PROT_EXEC ? 'x' : '-',
        q_flags & MAP_SHARED ? 's' : 'p',
        '\0'
      };

      mapping.flags = flags_tmp;
      mapping.filename = line_start + filename_offset;

      body(mapping, arg);

      return true;
    });
}
#endif

#if defined(__sun__)
bool DoIterateSolaris(void (*body)(const ProcMapping& mapping, void* arg), void* arg) {
  int fd;
  NO_INTR(fd = open("/proc/self/map", O_RDONLY));

  // This is based on MA_READ == 4, MA_WRITE == 2, MA_EXEC == 1
  static char kPerms[8][4] = {
    "---", "--x", "-w-", "-wx",
    "r--", "r-x", "rw-", "rwx" };

  static_assert(MA_READ == 4, "solaris MA_READ must equal 4");
  static_assert(MA_WRITE == 2, "solaris MA_WRITE must equal 2");
  static_assert(MA_EXEC == 1, "solaris MA_EXEC must equal 1");

  constexpr ssize_t kFilenameLen = PATH_MAX;
  char current_filename[kFilenameLen];

  int nread = 0;            // fill up buffer with text
  prmap_t mapinfo;

  for (;;) {
    NO_INTR(nread = read(fd, &mapinfo, sizeof(prmap_t)));
    if (nread != sizeof(prmap_t)) {
      CHECK_EQ(nread, 0);
      break;
    }

    char object_path[PATH_MAX + 1000];
    CHECK_LT(snprintf(object_path, sizeof(object_path),
                      "/proc/self/path/%s", mapinfo.pr_mapname),
             sizeof(object_path));
    ssize_t len = readlink(object_path, current_filename, kFilenameLen);
    if (len < 0) {
      len = 0;
    }
    CHECK_LT(len, kFilenameLen);
    current_filename[len] = '\0';

    ProcMapping mapping;
    memset(&mapping, 0, sizeof(mapping));

    mapping.start = mapinfo.pr_vaddr;
    mapping.end = mapinfo.pr_vaddr + mapinfo.pr_size;
    mapping.flags = kPerms[mapinfo.pr_mflags & 7];
    mapping.offset = mapinfo.pr_offset;
    mapping.filename = current_filename;

    body(mapping, arg);
  }

  close(fd);
  return true;
}
#endif

#if defined(PLATFORM_WINDOWS)
bool DoIterateWindows(void (*body)(const ProcMapping& mapping, void* arg), void* arg) {
  HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE |
                                             TH32CS_SNAPMODULE32,
                                             GetCurrentProcessId());
  if (snapshot == INVALID_HANDLE_VALUE) {
    return false;
  }

  MODULEENTRY32 mod_entry;
  memset(&mod_entry, 0, sizeof(mod_entry));

  ProcMapping mapping;
  memset(&mapping, 0, sizeof(mapping));
  static char kDefaultPerms[5] = "r-xp";
  BOOL ok;

  for (;;) {
    if (mod_entry.dwSize == 0) {  // only possible before first call
      mod_entry.dwSize = sizeof(mod_entry);
      ok = Module32First(snapshot, &mod_entry);
    } else {
      ok = Module32Next(snapshot, &mod_entry);
    }
    if (!ok) {
      break;
    }

    uint64_t base_addr = reinterpret_cast(mod_entry.modBaseAddr);
    mapping.start = base_addr;
    mapping.end = base_addr + mod_entry.modBaseSize;
    mapping.flags = kDefaultPerms;
    mapping.filename = mod_entry.szExePath;

    body(mapping, arg);
  }

  CloseHandle(snapshot);
  return true;
}
#endif  // defined(PLATFORM_WINDOWS)

#if defined(__MACH__)
// A templatized helper function instantiated for Mach (OS X) only.
// It can handle finding info for both 32 bits and 64 bits.
// Returns true if it successfully handled the hdr, false else.
template
bool NextExtMachHelper(const mach_header* hdr,
                              int current_image, int current_load_cmd,
                              uint64_t *start, uint64_t *end, const char **flags,
                              uint64_t *offset, const char **filename) {
  static char kDefaultPerms[5] = "r-xp";
  if (hdr->magic != kMagic)
    return false;
  const char* lc = (const char *)hdr + sizeof(MachHeader);
  // TODO(csilvers): make this not-quadradic (increment and hold state)
  for (int j = 0; j < current_load_cmd; j++)  // advance to *our* load_cmd
    lc += ((const load_command *)lc)->cmdsize;
  if (((const load_command *)lc)->cmd == kLCSegment) {
    const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image);
    const SegmentCommand* sc = (const SegmentCommand *)lc;
    if (start) *start = sc->vmaddr + dlloff;
    if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
    if (flags) *flags = kDefaultPerms;  // can we do better?
    if (offset) *offset = sc->fileoff;
    if (filename)
      *filename = const_cast(_dyld_get_image_name(current_image));
    return true;
  }

  return false;
}

bool DoIterateOSX(void (*body)(const ProcMapping& mapping, void* arg), void* arg) {
  int current_image = _dyld_image_count();   // count down from the top
  int current_load_cmd = -1;

  ProcMapping mapping;
  memset(&mapping, 0, sizeof(mapping));

reenter:
  for (; current_image >= 0; current_image--) {
    const mach_header* hdr = _dyld_get_image_header(current_image);
    if (!hdr) continue;
    if (current_load_cmd < 0)   // set up for this image
      current_load_cmd = hdr->ncmds;  // again, go from the top down

    // We start with the next load command (we've already looked at this one).
    for (current_load_cmd--; current_load_cmd >= 0; current_load_cmd--) {
#ifdef MH_MAGIC_64
      if (NextExtMachHelper(
            hdr, current_image, current_load_cmd,
            &mapping.start, &mapping.end,
            &mapping.flags,
            &mapping.offset, &mapping.filename)) {
        body(mapping, arg);
        goto reenter;
      }
#endif
      if (NextExtMachHelper(
            hdr, current_image, current_load_cmd,
            &mapping.start, &mapping.end,
            &mapping.flags,
            &mapping.offset, &mapping.filename)) {
        body(mapping, arg);
        goto reenter;
      }
    }
    // If we get here, no more load_cmd's in this image talk about
    // segments.  Go on to the next image.
  }

  return true;
}
#endif  // __MACH__

void FormatLine(tcmalloc::GenericWriter* writer,
                uint64_t start, uint64_t end, const char *flags,
                uint64_t offset, uint64_t inode,
                const char *filename, dev_t dev) {
  // We assume 'flags' looks like 'rwxp' or 'rwx'.
  char r = (flags && flags[0] == 'r') ? 'r' : '-';
  char w = (flags && flags[0] && flags[1] == 'w') ? 'w' : '-';
  char x = (flags && flags[0] && flags[1] && flags[2] == 'x') ? 'x' : '-';
  // p always seems set on linux, so we set the default to 'p', not '-'
  char p = (flags && flags[0] && flags[1] && flags[2] && flags[3] != 'p')
      ? '-' : 'p';

  writer->AppendF("%08" PRIx64 "-%08" PRIx64 " %c%c%c%c %08" PRIx64 " %02x:%02x %" PRIu64 " ",
                  start, end, r,w,x,p, offset,
                  static_cast(dev/256), static_cast(dev%256),
                  inode);
  writer->AppendStr(filename);
  writer->AppendStr("\n");
}

}  // anonymous namespace

bool DoForEachProcMapping(void (*body)(const ProcMapping& mapping, void* arg), void* arg) {
#if defined TCMALLOC_WANT_DL_ITERATE_PHDR
  auto callback = [&] (struct dl_phdr_info *info, size_t _size) -> int {
    ProcMapping mapping;
    memset(&mapping, 0, sizeof(mapping));
    uintptr_t addr = info->dlpi_addr;
    if (!info->dlpi_name || info->dlpi_name[0] == 0) {
      mapping.filename = tcmalloc::GetProgramInvocationName();
      if (!mapping.filename) {
        mapping.filename = "";
      }
    } else {
      mapping.filename = info->dlpi_name;
    }
    for (int i = 0; i < info->dlpi_phnum; i++) {
      auto phdr = info->dlpi_phdr + i;
      if (phdr->p_type != PT_LOAD) {
        continue;
      }
      uint64_t vaddr = phdr->p_vaddr + addr;
      uint64_t align = phdr->p_align;
      uint64_t offset = phdr->p_offset;
      uint64_t size = phdr->p_filesz;
      uint64_t start_adj = vaddr & (align - 1); // amount we need to round down to align start
      uint64_t end_adj = (~(vaddr + size) + 1) & (align - 1); // likewise, but for end of mapping

      vaddr -= start_adj;
      offset -= start_adj;
      size += start_adj + end_adj;
      CHECK_EQ((size & (align - 1)), 0);

      char flags[5] = "---p";
      auto fl = phdr->p_flags;
      if ((fl & PF_R)) {
        flags[0] = 'r';
      }
      if ((fl & PF_W)) {
        flags[1] = 'w';
      }
      if ((fl & PF_X)) {
        flags[2] = 'x';
      }

      mapping.start = vaddr;
      mapping.end = vaddr + size;
      mapping.flags = flags;
      mapping.offset = offset;
      mapping.inode = 0;

      body(mapping, arg);
    }

    return 0;
  };

  tcmalloc::FunctionRef ref{callback};
  (void)dl_iterate_phdr(ref.fn, ref.data);

  return true;
#elif defined(PLATFORM_WINDOWS)
  return DoIterateWindows(body, arg);
#elif defined(__MACH__)
  return DoIterateOSX(body, arg);
#elif defined(__sun__)
  return DoIterateSolaris(body, arg);
#elif defined(__QNXNTO__)
  return DoIterateQNX(body, arg);
#elif defined(__FreeBSD__)
  return DoIterateFreeBSD(body, arg);
#elif defined(__linux__) || defined(__NetBSD__)
  return DoIterateLinux("/proc/self/maps", body, arg);
#else
  return false;
#endif
}

void SaveProcSelfMaps(GenericWriter* writer) {
  ForEachProcMapping([writer] (const ProcMapping& mapping) {
    FormatLine(writer,
               mapping.start, mapping.end, mapping.flags,
               mapping.offset, mapping.inode,
               mapping.filename, 0);
  });
}

void SaveProcSelfMapsToRawFD(RawFD fd) {
  RawFDGenericWriter<> writer(fd);
  SaveProcSelfMaps(&writer);
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/base/proc_maps_iterator.h000066400000000000000000000062001513545575200235720ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef BASE_PROC_MAPS_ITERATOR_H_
#define BASE_PROC_MAPS_ITERATOR_H_
#include "config.h"

#include 

#include "base/generic_writer.h"
#include "base/logging.h"

namespace tcmalloc {

// ProcMapping struct contains description of proc/pid/maps entry as
// used by ForEachProcMapping below.
struct ProcMapping {
  uint64_t start;
  uint64_t end;
  const char* flags;
  uint64_t offset;
  uint64_t inode;
  const char* filename;
};

// Internal version of ForEachProcMapping below.
bool DoForEachProcMapping(void (*body)(const ProcMapping& mapping, void* arg), void* arg);

// Iterates VMA entries in /proc/self/maps (or similar on other
// OS-es). Returns false if open() failed.
template 
bool ForEachProcMapping(const Body& body) {
  return DoForEachProcMapping([] (const ProcMapping& mapping, void* arg) {
    const Body& body = *const_cast(static_cast(arg));
    body(mapping);
  }, static_cast(const_cast(&body)));
}

// Helper to add the list of mapped shared libraries to a profile.
// Write formatted "/proc/self/maps" contents into a given `writer'.
//
// See man 5 proc (on GNU/Linux system), or Google for "linux man 5
// proc" and search proc/pid/maps entry there for description of
// format.
void SaveProcSelfMaps(GenericWriter* writer);
// Helper to add the list of mapped shared libraries to a profile.
// Write formatted "/proc/self/maps" contents into a given file
// descriptor.
void SaveProcSelfMapsToRawFD(RawFD fd);

}  // namespace tcmalloc

#endif  // BASE_PROC_MAPS_ITERATOR_H_
gperftools-gperftools-2.18/src/base/spinlock.cc000066400000000000000000000145101513545575200216610ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2006, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Sanjay Ghemawat
 */

#include 
#include "base/spinlock.h"
#include "base/spinlock_internal.h"
#include "base/sysinfo.h"   /* for GetSystemCPUsCount() */

#if defined(__linux__) && defined(__GNUC__) && (defined(__aarch64__) || defined(__arm64__))
#include 

#ifndef HWCAP_SB
#define HWCAP_SB  (1 << 29)
#endif  // HWCAP_SB

#endif

// NOTE on the Lock-state values:
//
// kSpinLockFree represents the unlocked state
// kSpinLockHeld represents the locked state with no waiters
// kSpinLockSleeper represents the locked state with waiters

static int adaptive_spin_count = 0;

namespace {

#if defined(__GNUC__) && (defined(__aarch64__) || defined(__arm64__))
bool arm_use_spin_delay_sb;
#endif

struct SpinLock_InitHelper {
  SpinLock_InitHelper() {
    // On multi-cpu machines, spin for longer before yielding
    // the processor or sleeping.  Reduces idle time significantly.
    if (GetSystemCPUsCount() > 1) {
      adaptive_spin_count = 1000;
    }

#if defined(__linux__) && defined(__GNUC__) && (defined(__aarch64__) || defined(__arm64__))
    // Set arm_use_spin_delay_sb variable to "true" to use `sb` if supported
    if ((getauxval(AT_HWCAP) & HWCAP_SB) != 0)
      arm_use_spin_delay_sb = true;
#endif
  }
};

// Hook into global constructor execution:
// We do not do adaptive spinning before that,
// but nothing lock-intensive should be going on at that time.
static SpinLock_InitHelper init_helper;

inline void SpinlockPause(void) {
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
  __asm__ __volatile__("rep; nop" : : );
#elif defined(__GNUC__) && (defined(__aarch64__) || defined(__arm64__))
  // Use SB instruction if available otherwise ISB
  if (PREDICT_TRUE(arm_use_spin_delay_sb)) {
    __asm__ __volatile__(".inst 0xd50330ff" : : ); // SB instruction encoding
  } else {
    __asm__ __volatile__("isb" : : );
  }
#endif
}

}  // unnamed namespace

// Monitor the lock to see if its value changes within some time
// period (adaptive_spin_count loop iterations). The last value read
// from the lock is returned from the method.
int SpinLock::SpinLoop() {
  int c = adaptive_spin_count;
  while (lockword_.load(std::memory_order_relaxed) != kSpinLockFree && --c > 0) {
    SpinlockPause();
  }
  int old = kSpinLockFree;
  lockword_.compare_exchange_strong(old, kSpinLockSleeper, std::memory_order_acquire);
  // note, that we try to set lock word to 'have sleeper' state might
  // look unnecessary, but:
  //
  // *) pay attention to second call to SpinLoop at the bottom of SlowLock loop below
  //
  // *) note, that we get there after sleeping in SpinLockDelay and
  //    getting woken by Unlock
  //
  // *) also note, that we don't "count" sleepers, so when unlock
  //    awakes us, it also sets lock word to "free". So we risk
  //    forgetting other sleepers. And to prevent this, we become
  //    "designated waker", by setting lock word to "have sleeper". So
  //    then when we unlock, we also wake up someone.
  return old;
}

void SpinLock::SlowLock() {
  int lock_value = SpinLoop();

  int lock_wait_call_count = 0;
  while (lock_value != kSpinLockFree) {
    // If the lock is currently held, but not marked as having a sleeper, mark
    // it as having a sleeper.
    if (lock_value == kSpinLockHeld) {
      // Here, just "mark" that the thread is going to sleep.  Don't
      // store the lock wait time in the lock as that will cause the
      // current lock owner to think it experienced contention. Note,
      // compare_exchange updates lock_value with previous value of
      // lock word.
      lockword_.compare_exchange_strong(lock_value, kSpinLockSleeper,
                                        std::memory_order_acquire);
      if (lock_value == kSpinLockHeld) {
        // Successfully transitioned to kSpinLockSleeper.  Pass
        // kSpinLockSleeper to the SpinLockDelay routine to properly indicate
        // the last lock_value observed.
        lock_value = kSpinLockSleeper;
      } else if (lock_value == kSpinLockFree) {
        // Lock is free again, so try and acquire it before sleeping.  The
        // new lock state will be the number of cycles this thread waited if
        // this thread obtains the lock.
        lockword_.compare_exchange_strong(lock_value, kSpinLockSleeper, std::memory_order_acquire);
        continue;  // skip the delay at the end of the loop
      }
    }

    // Wait for an OS specific delay.
    base::internal::SpinLockDelay(&lockword_, lock_value,
                                  ++lock_wait_call_count);
    // Spin again after returning from the wait routine to give this thread
    // some chance of obtaining the lock.
    lock_value = SpinLoop();
  }
}

void SpinLock::SlowUnlock() {
  // wake waiter if necessary
  base::internal::SpinLockWake(&lockword_, false);
}
gperftools-gperftools-2.18/src/base/spinlock.h000066400000000000000000000112631513545575200215250ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2006, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Sanjay Ghemawat
 */

// SpinLock is async signal safe.
// If used within a signal handler, all lock holders
// should block the signal even outside the signal handler.

#ifndef BASE_SPINLOCK_H_
#define BASE_SPINLOCK_H_

#include 

#include 
#include 

#include "base/basictypes.h"
#include "base/static_storage.h"
#include "base/thread_annotations.h"

class LOCKABLE SpinLock {
 public:
  constexpr SpinLock() : lockword_(kSpinLockFree) { }

  // Acquire this SpinLock.
  void Lock() EXCLUSIVE_LOCK_FUNCTION() {
    int old = kSpinLockFree;
    if (!lockword_.compare_exchange_weak(old, kSpinLockHeld, std::memory_order_acquire)) {
      SlowLock();
    }
  }

  // Try to acquire this SpinLock without blocking and return true if the
  // acquisition was successful.  If the lock was not acquired, false is
  // returned.  If this SpinLock is free at the time of the call, TryLock
  // will return true with high probability.
  bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
    int old = kSpinLockFree;
    return lockword_.compare_exchange_weak(old, kSpinLockHeld);
  }

  // Release this SpinLock, which must be held by the calling thread.
  void Unlock() UNLOCK_FUNCTION() {
    int prev_value = lockword_.exchange(kSpinLockFree, std::memory_order_release);
    if (prev_value != kSpinLockHeld) {
      // Speed the wakeup of any waiter.
      SlowUnlock();
    }
  }

  // Determine if the lock is held.  When the lock is held by the invoking
  // thread, true will always be returned. Intended to be used as
  // CHECK(lock.IsHeld()).
  bool IsHeld() const {
    return lockword_.load(std::memory_order_relaxed) != kSpinLockFree;
  }

 private:
  enum { kSpinLockFree = 0 };
  enum { kSpinLockHeld = 1 };
  enum { kSpinLockSleeper = 2 };

  std::atomic lockword_;

  void SlowLock();
  void SlowUnlock();
  int SpinLoop();

  DISALLOW_COPY_AND_ASSIGN(SpinLock);
};

// Corresponding locker object that arranges to acquire a spinlock for
// the duration of a C++ scope.
class SCOPED_LOCKABLE SpinLockHolder {
 private:
  SpinLock* lock_;
 public:
  explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l)
      : lock_(l) {
    l->Lock();
  }
  SpinLockHolder(const SpinLockHolder&) = delete;
  ~SpinLockHolder() UNLOCK_FUNCTION() {
    lock_->Unlock();
  }
};
// Catch bug where variable name is omitted, e.g. SpinLockHolder (&lock);
#define SpinLockHolder(x) static_assert(0)

namespace tcmalloc {

class TrivialOnce {
public:
  template 
  bool RunOnce(Body body) {
    auto done_atomic = reinterpret_cast*>(&done_flag_);
    if (done_atomic->load(std::memory_order_acquire) == 1) {
      return false;
    }

    SpinLockHolder h(lock_storage_.get());

    if (done_atomic->load(std::memory_order_relaxed) == 1) {
      // barrier provided by lock
      return false;
    }
    body();
    done_atomic->store(1, std::memory_order_release);
    return true;
  }

private:
  int done_flag_;
  StaticStorage lock_storage_;
};

static_assert(std::is_trivial::value == true, "");

}  // namespace tcmalloc


#endif  // BASE_SPINLOCK_H_
gperftools-gperftools-2.18/src/base/spinlock_internal.cc000066400000000000000000000067341513545575200235660ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2010, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// The OS-specific header included below must provide two calls:
// base::internal::SpinLockDelay() and base::internal::SpinLockWake().
// See spinlock_internal.h for the spec of SpinLockWake().

// void SpinLockDelay(std::atomic *w, int32_t value, int loop)
// SpinLockDelay() generates an apprproate spin delay on iteration "loop" of a
// spin loop on location *w, whose previously observed value was "value".
// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
// or may wait for a delay that can be truncated by a call to SpinlockWake(w).
// In all cases, it must return in bounded time even if SpinlockWake() is not
// called.

#include "base/spinlock_internal.h"

// forward declaration for use by spinlock_*-inl.h
namespace base { namespace internal { static int SuggestedDelayNS(int loop); }}

#if defined(_WIN32)
#include "base/spinlock_win32-inl.h"
#elif defined(__linux__)
#include "base/spinlock_linux-inl.h"
#else
#include "base/spinlock_posix-inl.h"
#endif

namespace base {
namespace internal {

// Return a suggested delay in nanoseconds for iteration number "loop"
static int SuggestedDelayNS(int loop) {
  // Weak pseudo-random number generator to get some spread between threads
  // when many are spinning.
  static volatile uint64_t rand;
  uint64_t r = rand;
  r = 0x5deece66dLL * r + 0xb;   // numbers from nrand48()
  rand = r;

  r <<= 16;   // 48-bit random number now in top 48-bits.
  if (loop < 0 || loop > 32) {   // limit loop to 0..32
    loop = 32;
  }
  // loop>>3 cannot exceed 4 because loop cannot exceed 32.
  // Select top 20..24 bits of lower 48 bits,
  // giving approximately 0ms to 16ms.
  // Mean is exponential in loop for first 32 iterations, then 8ms.
  // The futex path multiplies this by 16, since we expect explicit wakeups
  // almost always on that path.
  return r >> (44 - (loop >> 3));
}

} // namespace internal
} // namespace base
gperftools-gperftools-2.18/src/base/spinlock_internal.h000066400000000000000000000040631513545575200234210ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2010, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * This file is an internal part spinlock.cc and once.cc
 * It may not be used directly by code outside of //base.
 */

#ifndef BASE_SPINLOCK_INTERNAL_H_
#define BASE_SPINLOCK_INTERNAL_H_

#include 

#include 

#include "base/basictypes.h"

namespace base {
namespace internal {

void SpinLockWake(std::atomic *w, bool all);
void SpinLockDelay(std::atomic *w, int32_t value, int loop);

} // namespace internal
} // namespace base
#endif
gperftools-gperftools-2.18/src/base/spinlock_linux-inl.h000066400000000000000000000070061513545575200235240ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * This file is a Linux-specific part of spinlock_internal.cc
 */

#include 
#include 
#include 
#include 
#include 
#include 

#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_PRIVATE_FLAG 128

// Note: Instead of making direct system calls that are inlined, we rely
//       on the syscall() function in glibc to do the right thing.

static bool have_futex;
static int futex_private_flag = FUTEX_PRIVATE_FLAG;

namespace {
static struct InitModule {
  InitModule() {
    int x = 0;
    // futexes are ints, so we can use them only when
    // that's the same size as the lockword_ in SpinLock.
    have_futex = (syscall(__NR_futex, &x, FUTEX_WAKE, 1, nullptr, nullptr, 0) >= 0);
    if (have_futex && syscall(__NR_futex, &x, FUTEX_WAKE | futex_private_flag,
                              1, nullptr, nullptr, 0) < 0) {
      futex_private_flag = 0;
    }
  }
} init_module;

}  // anonymous namespace


namespace base {
namespace internal {

void SpinLockDelay(std::atomic *w, int32_t value, int loop) {
  if (loop != 0) {
    int save_errno = errno;
    struct timespec tm;
    tm.tv_sec = 0;
    if (have_futex) {
      tm.tv_nsec = base::internal::SuggestedDelayNS(loop);
    } else {
      tm.tv_nsec = 2000001;   // above 2ms so linux 2.4 doesn't spin
    }
    if (have_futex) {
      tm.tv_nsec *= 16;  // increase the delay; we expect explicit wakeups
      syscall(__NR_futex, reinterpret_cast(w),
              FUTEX_WAIT | futex_private_flag, value,
              reinterpret_cast(&tm), nullptr, 0);
    } else {
      nanosleep(&tm, nullptr);
    }
    errno = save_errno;
  }
}

void SpinLockWake(std::atomic *w, bool all) {
  if (have_futex) {
    syscall(__NR_futex, reinterpret_cast(w),
            FUTEX_WAKE | futex_private_flag, all ? INT_MAX : 1, nullptr, nullptr, 0);
  }
}

} // namespace internal
} // namespace base
gperftools-gperftools-2.18/src/base/spinlock_posix-inl.h000066400000000000000000000044251513545575200235310ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * This file is a Posix-specific part of spinlock_internal.cc
 */

#include 
#include 
#ifdef HAVE_SCHED_H
#include       /* For sched_yield() */
#endif
#include        /* For nanosleep() */

namespace base {
namespace internal {

void SpinLockDelay(std::atomic *w, int32_t value, int loop) {
  int save_errno = errno;
  if (loop == 0) {
  } else if (loop == 1) {
    sched_yield();
  } else {
    struct timespec tm;
    tm.tv_sec = 0;
    tm.tv_nsec = base::internal::SuggestedDelayNS(loop);
    nanosleep(&tm, nullptr);
  }
  errno = save_errno;
}

void SpinLockWake(std::atomic  *w, bool all) {
}

} // namespace internal
} // namespace base
gperftools-gperftools-2.18/src/base/spinlock_win32-inl.h000066400000000000000000000044031513545575200233250ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * This file is a Win32-specific part of spinlock_internal.cc
 */


#include 

#ifdef _MSC_VER
#   pragma comment(lib, "Synchronization.lib")
#endif

namespace base {
namespace internal {

void SpinLockDelay(std::atomic *w, int32_t value, int loop) {
  if (loop != 0) {
    auto wait_ns = static_cast(base::internal::SuggestedDelayNS(loop)) * 16;
    auto wait_ms = wait_ns / 1000000;

    WaitOnAddress(w, &value, 4, static_cast(wait_ms));
  }
}

void SpinLockWake(std::atomic *w, bool all) {
  if (all) {
    WakeByAddressAll((void*)w);
  } else {
    WakeByAddressSingle((void*)w);
  }
}

} // namespace internal
} // namespace base
gperftools-gperftools-2.18/src/base/static_storage.h000066400000000000000000000042271513545575200227200ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef BASE_STATIC_STORAGE_H_
#define BASE_STATIC_STORAGE_H_
#include "config.h"

#include 

#include 

namespace tcmalloc {

template 
class StaticStorage {
public:
  T* get() {
    return reinterpret_cast(bytes_);
  }
  const T* get() const {
    return reinterpret_cast(bytes_);
  }

  template 
  T* Construct(U&&... u) {
    return new (bytes_) T(std::forward(u)...);
  }
private:
  alignas(alignof(T)) uint8_t bytes_[sizeof(T)];
};

}  // namespace tcmalloc

#endif  // BASE_STATIC_STORAGE_H_
gperftools-gperftools-2.18/src/base/stl_allocator.h000066400000000000000000000071531513545575200225500ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2006, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Maxim Lifantsev
 */


#ifndef BASE_STL_ALLOCATOR_H_
#define BASE_STL_ALLOCATOR_H_

#include 

#include    // for ptrdiff_t

#include "base/logging.h"

// Generic allocator class for STL objects
// that uses a given type-less allocator Alloc, which must provide:
//   static void* Alloc::Allocate(size_t size);
//   static void Alloc::Free(void* ptr, size_t size);
//
// STL_Allocator provides the same thread-safety
// guarantees as MyAlloc.
//
// Usage example:
//   set, STL_Allocator > my_set;
// CAVEAT: Parts of the code below are probably specific
//         to the STL version(s) we are using.
//         The code is simply lifted from what std::allocator<> provides.
template 
class STL_Allocator {
 public:
  typedef size_t     size_type;
  typedef ptrdiff_t  difference_type;
  typedef T*         pointer;
  typedef const T*   const_pointer;
  typedef T&         reference;
  typedef const T&   const_reference;
  typedef T          value_type;

  template  struct rebind {
    typedef STL_Allocator other;
  };

  STL_Allocator() { }
  STL_Allocator(const STL_Allocator&) { }
  template  STL_Allocator(const STL_Allocator&) { }
  ~STL_Allocator() { }

  pointer address(reference x) const { return &x; }
  const_pointer address(const_reference x) const { return &x; }

  pointer allocate(size_type n, const void* = 0) {
    RAW_DCHECK((n * sizeof(T)) / sizeof(T) == n, "n is too big to allocate");
    return static_cast(Alloc::Allocate(n * sizeof(T)));
  }
  void deallocate(pointer p, size_type n) { Alloc::Free(p, n * sizeof(T)); }

  size_type max_size() const { return size_t(-1) / sizeof(T); }

  void construct(pointer p, const T& val) { ::new(p) T(val); }
  void construct(pointer p) { ::new(p) T(); }
  void destroy(pointer p) { p->~T(); }

  // There's no state, so these allocators are always equal
  bool operator==(const STL_Allocator&) const { return true; }
};

#endif  // BASE_STL_ALLOCATOR_H_
gperftools-gperftools-2.18/src/base/sysinfo.cc000066400000000000000000000311141513545575200215300ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include 
#if (defined(_WIN32) || defined(__MINGW32__)) && !defined(__CYGWIN__) && !defined(__CYGWIN32)
# define PLATFORM_WINDOWS 1
#endif

#include "base/commandlineflags.h"
#include "base/environ.h"
#include "base/logging.h"
#include "base/memmap.h"
#include "base/sysinfo.h"

#include 

#include    // for getenv()
#include     // for snprintf(), sscanf()
#include    // for memmove(), memchr(), etc.
#include     // for open()
#ifdef HAVE_UNISTD_H
#include         // for PATH_MAX
#include    // for read()
#endif

#if defined(__FreeBSD__)
#include 
#endif

#ifdef __MACH__
#include    // for GetProgramInvocationName()
#endif

// ----------------------------------------------------------------------
// GetenvBeforeMain()
// GetUniquePathFromEnv()
//    Some non-trivial getenv-related functions.
// ----------------------------------------------------------------------

// NOTE, we used to have very special code for accessing environment
// (potentially) early, but in practice it is safe to access even very
// early (with notable exception of windows, as usual).
#ifndef PLATFORM_WINDOWS
const char* GetenvBeforeMain(const char* name) {
  return getenv(name);
}
#else  // PLATFORM_WINDOWS

// One windows we could use C runtime environment access or more
// "direct" GetEnvironmentVariable. But, notably, their "ASCII"
// variant does memory allocation. So we resort to using "wide"/utf16
// environment access. And we assume all our variables will be
// ascii-valued (both variable names and values). In future if/when we
// deal with filesystem paths we may have to do utf8 (here and FS
// access codes), but not today.
//
// We also use static (so thread-hostile) buffer since users of this
// function assume static storage. This implies subsequent calls to
// this function "break" values returned from previous calls. We're
// fine with that too.
const char* GetenvBeforeMain(const char* name) {
  const int namelen = strlen(name);

  static constexpr int kBufSize = 1024;
  // This is the buffer we'll return from here. So it is static. See
  // above.
  static char envvar_buf[kBufSize];

  // First, we convert variable name to windows 'wide' chars.
  static constexpr int kNameBufSize = 256;
  WCHAR wname[kNameBufSize];

  if (namelen >= 256) {
    return nullptr;
  }

  for (int i = 0; i <= namelen; i++) {
    wname[i] = static_cast(name[i]);
  }

  // Then we call environment variable access routine.
  WCHAR wide_envvar_buf[kBufSize];  // enough to hold any envvar we care about
  size_t used_buf;

  if (!(used_buf = GetEnvironmentVariableW(wname, wide_envvar_buf, kBufSize))) {
    return nullptr;
  }
  used_buf++; // include terminating \0 character.

  // Then we convert variable value, if any, to 7-bit ascii.
  for (size_t i = 0; i < used_buf ; i++) {
    auto wch = wide_envvar_buf[i];
    if ((wch >> 7)) {
      // If we see any non-ascii char, we silently assume no env
      // variable exists.
      return nullptr;
    }
    envvar_buf[i] = wch;
  }

  return envvar_buf;
}

#endif  // !PLATFORM_WINDOWS

extern "C" {
  const char* TCMallocGetenvSafe(const char* name) {
    return GetenvBeforeMain(name);
  }
}

// HPC environment auto-detection
// For HPC applications (MPI, OpenSHMEM, etc), it is typical for multiple
// processes not engaged in parent-child relations to be executed on the
// same host.
// In order to enable gperftools to analyze them, these processes need to be
// assigned individual file paths for the files being used.
// The function below is trying to discover well-known HPC environments and
// take advantage of that environment to generate meaningful profile filenames
//
// Returns true iff we need to append process pid to
// GetUniquePathFromEnv value. Second and third return values are
// strings to be appended to path for extra identification.
static std::tuple QueryHPCEnvironment() {
  auto mk = [] (bool a, const char* b, const char* c) {
    // We have to work around gcc 5 bug in tuple constructor. It
    // doesn't let us do {a, b, c}
    //
    // TODO(2023-09-27): officially drop gcc 5 support
    return std::make_tuple(std::move(a), std::move(b), std::move(c));
  };

  // Check for the PMIx environment
  const char* envval = getenv("PMIX_RANK");
  if (envval != nullptr && *envval != 0) {
    // PMIx exposes the rank that is convenient for process identification
    // Don't append pid, since we have rank to differentiate.
    return mk(false, ".rank-", envval);
  }

  // Check for the Slurm environment
  envval = getenv("SLURM_JOB_ID");
  if (envval != nullptr && *envval != 0) {
    // Slurm environment detected
    const char* procid = getenv("SLURM_PROCID");
    if (procid != nullptr && *procid != 0) {
      // Use Slurm process ID to differentiate
      return mk(false, ".slurmid-", procid);
    }
    // Need to add PID to avoid conflicts
    return mk(true, "", "");
  }

  // Check for Open MPI environment
  envval = getenv("OMPI_HOME");
  if (envval != nullptr && *envval != 0) {
    return mk(true, "", "");
  }

  // Check for Hydra process manager (MPICH)
  envval = getenv("PMI_RANK");
  if (envval != nullptr && *envval != 0) {
    return mk(false, ".rank-", envval);
  }

  // No HPC environment was detected
  return mk(false, "", "");
}

namespace {
int GetPID() {
#ifdef _WIN32
  return _getpid();
#else
  return getpid();
#endif
}
}  // namespace

// This takes as an argument an environment-variable name (like
// CPUPROFILE) whose value is supposed to be a file-path, and sets
// path to that path, and returns true.  If the env var doesn't exist,
// or is the empty string, leave path unchanged and returns false.
// The reason this is non-trivial is that this function handles munged
// pathnames.  Here's why:
//
// If we're a child process of the 'main' process, we can't just use
// getenv("CPUPROFILE") -- the parent process will be using that path.
// Instead we append our pid to the pathname.  How do we tell if we're
// a child process? Ideally we'd set an environment variable that all
// our children would inherit. We use direct environ access, because
// {set,put}env will recurse back to malloc. While none of this is
// strictly speaking thread-safe (setenv included), we're calling this
// early enough where threads are usually not running. So mutating
// environ is safe enough. I also checked several OSes, and other than
// windows, it really is supported to manually override environ.
//
// We put CPUPROFILE_USE_PID=1 marker for the children.
bool GetUniquePathFromEnv(const char* env_name, char* path) {
  char* envval = getenv(env_name);

  if (envval == nullptr || *envval == '\0') {
    return false;
  }

  const char* append1 = "";
  const char* append2 = "";
  bool pidIsForced;
  std::tie(pidIsForced, append1, append2) = QueryHPCEnvironment();

  // Generate the "forcing" environment variable name in a form of
  // _USE_PID that requests PID to be used in the file names
  char forceVarName[256];
  snprintf(forceVarName, sizeof(forceVarName), "%s_USE_PID", env_name);

#if defined(PLATFORM_WINDOWS)
  pidIsForced = true;
#else
  pidIsForced = pidIsForced || EnvToBool(forceVarName, false);
  if (!pidIsForced) {
    // As noted above, we want to arrange children of this process to
    // append pid to their file names.
    tcmalloc::SafeSetEnv(forceVarName, "1");
  }
#endif

  if (pidIsForced) {
    snprintf(path, PATH_MAX, "%s%s%s_%d",
             envval, append1, append2, GetPID());
  } else {
    snprintf(path, PATH_MAX, "%s%s%s", envval, append1, append2);
  }

  return true;
}

int GetSystemCPUsCount()
{
#if defined(PLATFORM_WINDOWS)
  // Get the number of processors.
  SYSTEM_INFO info;
  GetSystemInfo(&info);
  return  info.dwNumberOfProcessors;
#else
  long rv = sysconf(_SC_NPROCESSORS_ONLN);
  if (rv < 0) {
    return 1;
  }
  return static_cast(rv);
#endif
}

namespace {

#ifndef _WIN32
inline // NOTE: inline makes us avoid unused function warning
const char* readlink_strdup(const char* path) {
  int sz = 1024;
  char* retval = nullptr;
  for (;;) {
    if (INT_MAX / 2 <= sz) {
      free(retval);
      retval = nullptr;
      break;
    }
    sz *= 2;
    retval = static_cast(realloc(retval, sz));
    int rc = readlink(path, retval, sz);
    if (rc < 0) {
      perror("GetProgramInvocationName:readlink");
      free(retval);
      retval = nullptr;
      break;
    }
    if (rc < sz) {
      retval[rc] = 0;
      break;
    }
    // repeat if readlink may have truncated it's output
  }
  return retval;
}
#endif  // _WIN32

}  // namespace

namespace tcmalloc {

// Returns nullptr if we're on an OS where we can't get the invocation name.
// Using a static var is ok because we're not called from a thread.
const char* GetProgramInvocationName() {
#if defined(__linux__) || defined(__NetBSD__)
  // Those systems have functional procfs. And we can simply readlink
  // /proc/self/exe.
  static const char* argv0 = readlink_strdup("/proc/self/exe");
  return argv0;
#elif defined(__sun__)
  static const char* argv0 = readlink_strdup("/proc/self/path/a.out");
  return argv0;
#elif defined(HAVE_PROGRAM_INVOCATION_NAME)
  extern char* program_invocation_name;  // gcc provides this
  return program_invocation_name;
#elif defined(__MACH__)
  // We don't want to allocate memory for this since we may be
  // calculating it when memory is corrupted.
  static char program_invocation_name[PATH_MAX];
  if (program_invocation_name[0] == '\0') {  // first time calculating
    uint32_t length = sizeof(program_invocation_name);
    if (_NSGetExecutablePath(program_invocation_name, &length))
      return nullptr;
  }
  return program_invocation_name;
#elif defined(__FreeBSD__)
  static char program_invocation_name[PATH_MAX];
  size_t len = sizeof(program_invocation_name);
  static const int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
  if (!sysctl(name, 4, program_invocation_name, &len, nullptr, 0))
    return program_invocation_name;
  return nullptr;
#else
  return nullptr; // figure out a way to get argv[0]
#endif
}

void SafeSetEnv(const char* name, const char* value) {
  size_t env_size = 1; // 1 for terminating nullptr entry
  for (char** p = environ; *p != nullptr; p++) {
    env_size++;
  }

  size_t name_size = strlen(name);
  size_t value_size = strlen(value);
  size_t namevalue_size = name_size + value_size + 2; // +2 is for '=' and '\0'
  size_t new_env_size_bytes = (env_size + 1) * sizeof(char*);
  MMapResult mres = tcmalloc::MapAnonymous(new_env_size_bytes + namevalue_size);
  CHECK(mres.success);
  char* added_pair = static_cast(mres.addr) + new_env_size_bytes;
  {
    // copy name and value bytes
    char* p = added_pair;
    memcpy(p, name, name_size);
    p += name_size;
    *p++ = '=';
    memcpy(p, value, value_size);
    p += value_size;
    *p++ = '\0';
    CHECK(p - added_pair == namevalue_size);
  }

  char** new_env = static_cast(mres.addr);
  new_env[0] = added_pair;
  memcpy(new_env + 1, environ, env_size * sizeof(char*));

  environ = new_env;
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/base/sysinfo.h000066400000000000000000000065411513545575200214000ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// All functions here are thread-hostile due to file caching unless
// commented otherwise.

#ifndef _SYSINFO_H_
#define _SYSINFO_H_

#include 

#include     // for size_t
#include 
#include     // for PATH_MAX

#include "base/basictypes.h"

// This getenv function is safe to call before the C runtime is
// initialized.  On Windows, it utilizes GetEnvironmentVariableW()
// (and the we handle some trivial naive utf16-to-ascii
// conversion). On rest platforms it actually just uses getenv which
// appears to be safe to use from malloc-related contexts.
const char* GetenvBeforeMain(const char* name);

// This takes as an argument an environment-variable name (like
// CPUPROFILE) whose value is supposed to be a file-path, and sets
// path to that path, and returns true.  Non-trivial for surprising
// reasons, as documented in sysinfo.cc.  path must have space PATH_MAX.
bool GetUniquePathFromEnv(const char* env_name, char* path);

int GetSystemCPUsCount();


namespace tcmalloc {
ATTRIBUTE_VISIBILITY_HIDDEN const char* GetProgramInvocationName();

// SafeSetEnv is like setenv, but avoiding malloc or any locks. Only
// works on UNIXy systems. Few things to note:
//
// * just like setenv, it is totally thread-hostile. We use it in some
//   very early initialization (via GetUniquePathFromEnv), where it is
//   okay-ish to assume single thread.
//
// * it sorta leaks memory. It works by mmap-ing memory for the new
//   environ and name=value pair and overwriting environ
//   variable. Successive SafeSetEnv will leak environ memory
//   allocated by the previous invokations. So shouldn't be big deal.
ATTRIBUTE_VISIBILITY_HIDDEN void SafeSetEnv(const char* name, const char* value);
}  // namespace tcmalloc

#endif   /* #ifndef _SYSINFO_H_ */
gperftools-gperftools-2.18/src/base/thread_annotations.h000066400000000000000000000136121513545575200235670ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Le-Chun Wu
//
// This header file contains the macro definitions for thread safety
// annotations that allow the developers to document the locking policies
// of their multi-threaded code. The annotations can also help program
// analysis tools to identify potential thread safety issues.
//
// The annotations are implemented using clang's "attributes" extension.
// Using the macros defined here instead of the raw clang attributes allows
// for portability and future compatibility.
//
// This functionality is not yet fully implemented in perftools,
// but may be one day.

#ifndef BASE_THREAD_ANNOTATIONS_H_
#define BASE_THREAD_ANNOTATIONS_H_


#if defined(__clang__)
#define THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op
#endif


// Document if a shared variable/field needs to be protected by a lock.
// GUARDED_BY allows the user to specify a particular lock that should be
// held when accessing the annotated variable, while GUARDED_VAR only
// indicates a shared variable should be guarded (by any lock). GUARDED_VAR
// is primarily used when the client cannot express the name of the lock.
#define GUARDED_BY(x)          THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define GUARDED_VAR            THREAD_ANNOTATION_ATTRIBUTE__(guarded)

// Document if the memory location pointed to by a pointer should be guarded
// by a lock when dereferencing the pointer. Similar to GUARDED_VAR,
// PT_GUARDED_VAR is primarily used when the client cannot express the name
// of the lock. Note that a pointer variable to a shared memory location
// could itself be a shared variable. For example, if a shared global pointer
// q, which is guarded by mu1, points to a shared memory location that is
// guarded by mu2, q should be annotated as follows:
//     int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
#define PT_GUARDED_BY(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded_by(x))
#define PT_GUARDED_VAR \
  THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded)

// Document the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
// to establish an acquisition order, only one of them needs the annotation.
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
// and ACQUIRED_BEFORE.)
#define ACQUIRED_AFTER(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x))
#define ACQUIRED_BEFORE(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x))

// The following three annotations document the lock requirements for
// functions/methods.

// Document if a function expects certain locks to be held before it is called
#define EXCLUSIVE_LOCKS_REQUIRED(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))

#define SHARED_LOCKS_REQUIRED(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(x))

// Document the locks acquired in the body of the function. These locks
// cannot be held when calling this function (as google3's Mutex locks are
// non-reentrant).
#define LOCKS_EXCLUDED(x) \
  THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(x))

// Document the lock the annotated function returns without acquiring it.
#define LOCK_RETURNED(x)       THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))

// Document if a class/type is a lockable type (such as the Mutex class).
#define LOCKABLE               THREAD_ANNOTATION_ATTRIBUTE__(lockable)

// Document if a class is a scoped lockable type (such as the MutexLock class).
#define SCOPED_LOCKABLE        THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)

// The following annotations specify lock and unlock primitives.
#define EXCLUSIVE_LOCK_FUNCTION(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))

#define SHARED_LOCK_FUNCTION(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))

#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))

#define SHARED_TRYLOCK_FUNCTION(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))

#define UNLOCK_FUNCTION(...) \
  THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))

// An escape hatch for thread safety analysis to ignore the annotated function.
#define NO_THREAD_SAFETY_ANALYSIS \
  THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)

#endif  // BASE_THREAD_ANNOTATIONS_H_
gperftools-gperftools-2.18/src/base/threading.h000066400000000000000000000115071513545575200216510ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2024, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef THREADING_H_
#define THREADING_H_

#include 
#include "base/basictypes.h"

#ifdef _WIN32 // Should cover both toolchains on Windows - MSVC & MINGW

namespace tcmalloc {

using TlsKey = DWORD;

constexpr inline TlsKey kInvalidTLSKey = TLS_OUT_OF_INDEXES;

ATTRIBUTE_VISIBILITY_HIDDEN TlsKey WinTlsKeyCreate(void (*destr_fn)(void*));  /* windows/port.cc */

ATTRIBUTE_VISIBILITY_HIDDEN inline int CreateTlsKey(TlsKey *pkey, void (*destructor)(void*)) {
  TlsKey key = WinTlsKeyCreate(destructor);

  if (key == TLS_OUT_OF_INDEXES) {
    return GetLastError();
  }

  *(pkey) = key;
  return 0;
}

ATTRIBUTE_VISIBILITY_HIDDEN inline void* GetTlsValue(TlsKey key) {
  return TlsGetValue(key);
}

ATTRIBUTE_VISIBILITY_HIDDEN inline int SetTlsValue(TlsKey key, const void* value) {
  return !TlsSetValue(key, (LPVOID)value);
}

ATTRIBUTE_VISIBILITY_HIDDEN inline uintptr_t SelfThreadId() {
  // Notably, windows/ms crt errno access recurses into malloc (!), so
  // we have to do this. But this is fast and good enough.
  return static_cast(GetCurrentThreadId());
}

} // namespace tcmalloc

#else

#include 
#include 

namespace tcmalloc {

using TlsKey = pthread_key_t;

// I've checked several implementations and they're all implementing
// pthread_key_t as some kind of integer type. Sometimes signed,
// sometimes unsigned, and occasionally of different width
// (basically, int or long).
//
// Notably, however, POSIX is explicitly _not_ requiring
// pthread_key_t to be of some integer type. So we're somewhat into
// non-portable territory here. But in practice we should be okay,
// not just given current practice, but also keeping in mind how to
// "reasonably" implement thread-specific values. Some applies, sadly, to
// C11 tss_t type.
//
// Another potentially tricky aspect is what values to consider
// invalid. POSIX also says nothing about this, sadly. Solaris has
// nonportable PTHREAD_ONCE_KEY_NP, which would be sensible to have
// in standard (even without pthread_key_create_once_np), but we
// have what we have. It's value is (int)(-1). And, indeed, -1 seems
// like most sensible value.
constexpr inline TlsKey kInvalidTLSKey = static_cast(~uintptr_t{0});
static_assert(sizeof(pthread_key_t) <= sizeof(uintptr_t));

ATTRIBUTE_VISIBILITY_HIDDEN inline int CreateTlsKey(TlsKey *pkey, void (*destructor)(void*)) {
  int err = pthread_key_create(pkey, destructor);
  if (err != 0) {
    return err;
  }
  // It is super-implausible that we'll be able to create "invalid"
  // tls key value, but just in case, we check and re-create if we end
  // up getting one.
  if (*pkey != kInvalidTLSKey) {
    return 0;
  }

  return CreateTlsKey(pkey, destructor);
}

ATTRIBUTE_VISIBILITY_HIDDEN inline void* GetTlsValue(TlsKey key) {
  return pthread_getspecific(key);
}

ATTRIBUTE_VISIBILITY_HIDDEN inline int SetTlsValue(TlsKey key, const void* value) {
  return pthread_setspecific(key, value);
}

ATTRIBUTE_VISIBILITY_HIDDEN inline uintptr_t SelfThreadId() {
  // Most platforms (with notable exception of windows C runtime) can
  // use address of errno as a quick and portable and recursion-free
  // thread identifier.
  return reinterpret_cast(&errno);
}

} // namespace tcmalloc

#endif

#endif // THREADING_H_
gperftools-gperftools-2.18/src/base/vdso_support.cc000066400000000000000000000121011513545575200226000ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Paul Pluzhnikov
//
// Allow dynamic symbol lookup in the kernel VDSO page.
//
// VDSOSupport -- a class representing kernel VDSO (if present).
//

#include "base/vdso_support.h"

#ifdef HAVE_VDSO_SUPPORT     // defined in vdso_support.h

#include 
#include    // for ptrdiff_t

#include "base/logging.h"
#include "base/dynamic_annotations.h"
#include "base/basictypes.h"

#ifndef AT_SYSINFO_EHDR
#define AT_SYSINFO_EHDR 33
#endif

namespace base {

const void *VDSOSupport::vdso_base_ = ElfMemImage::kInvalidBase;
VDSOSupport::VDSOSupport()
    // If vdso_base_ is still set to kInvalidBase, we got here
    // before VDSOSupport::Init has been called. Call it now.
    : image_(vdso_base_ == ElfMemImage::kInvalidBase ? Init() : vdso_base_) {
}

// NOTE: we can't use GoogleOnceInit() below, because we can be
// called by tcmalloc, and none of the *once* stuff may be functional yet.
//
// In addition, we hope that the VDSOSupportHelper constructor
// causes this code to run before there are any threads, and before
// InitGoogle() has executed any chroot or setuid calls.
//
// Finally, even if there is a race here, it is harmless, because
// the operation should be idempotent.
const void *VDSOSupport::Init() {
  if (vdso_base_ == ElfMemImage::kInvalidBase) {
    // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
    // on stack, and so glibc works as if VDSO was not present.
    // But going directly to kernel via /proc/self/auxv below bypasses
    // Valgrind zapping. So we check for Valgrind separately.
    if (RunningOnValgrind()) {
      vdso_base_ = nullptr;
      return nullptr;
    }
    int fd = open("/proc/self/auxv", O_RDONLY);
    if (fd == -1) {
      // Kernel too old to have a VDSO.
      vdso_base_ = nullptr;
      return nullptr;
    }
    ElfW(auxv_t) aux;
    while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
      if (aux.a_type == AT_SYSINFO_EHDR) {
        static_assert(sizeof(vdso_base_) == sizeof(aux.a_un.a_val),
                      "unexpected sizeof(pointer) != sizeof(a_val)");
        vdso_base_ = reinterpret_cast(aux.a_un.a_val);
        break;
      }
    }
    close(fd);
    if (vdso_base_ == ElfMemImage::kInvalidBase) {
      // Didn't find AT_SYSINFO_EHDR in auxv[].
      vdso_base_ = nullptr;
    }
  }
  return vdso_base_;
}

const void *VDSOSupport::SetBase(const void *base) {
  CHECK(base != ElfMemImage::kInvalidBase);
  const void *old_base = vdso_base_;
  vdso_base_ = base;
  image_.Init(base);
  return old_base;
}

bool VDSOSupport::LookupSymbol(const char *name,
                               const char *version,
                               int type,
                               SymbolInfo *info) const {
  return image_.LookupSymbol(name, version, type, info);
}

bool VDSOSupport::LookupSymbolByAddress(const void *address,
                                        SymbolInfo *info_out) const {
  return image_.LookupSymbolByAddress(address, info_out);
}

// We need to make sure VDSOSupport::Init() is called before
// the main() runs, since it might do something like setuid or
// chroot.  If VDSOSupport
// is used in any global constructor, this will happen, since
// VDSOSupport's constructor calls Init.  But if not, we need to
// ensure it here, with a global constructor of our own.  This
// is an allowed exception to the normal rule against non-trivial
// global constructors.
static class VDSOInitHelper {
 public:
  VDSOInitHelper() { VDSOSupport::Init(); }
} vdso_init_helper;
}

#endif  // HAVE_VDSO_SUPPORT
gperftools-gperftools-2.18/src/base/vdso_support.h000066400000000000000000000117671513545575200224630ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Paul Pluzhnikov
//
// Allow dynamic symbol lookup in the kernel VDSO page.
//
// VDSO stands for "Virtual Dynamic Shared Object" -- a page of
// executable code, which looks like a shared library, but doesn't
// necessarily exist anywhere on disk, and which gets mmap()ed into
// every process by kernels which support VDSO, such as 2.6.x for 32-bit
// executables, and 2.6.24 and above for 64-bit executables.
//
// More details could be found here:
// http://www.trilithium.com/johan/2005/08/linux-gate/
//
// VDSOSupport -- a class representing kernel VDSO (if present).
//
// Example usage:
//  VDSOSupport vdso;
//  VDSOSupport::SymbolInfo info;
//  typedef (*FN)(unsigned *, void *, void *);
//  FN fn = nullptr;
//  if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
//     fn = reinterpret_cast(info.address);
//  }

#ifndef BASE_VDSO_SUPPORT_H_
#define BASE_VDSO_SUPPORT_H_

#include 

#include "base/elf_mem_image.h" // IWYU pragma: keep

#ifdef HAVE_ELF_MEM_IMAGE

// See elf_mem_image.h. We only define HAVE_ELF_MEM_IMAGE for Linux/PPC.
#define HAVE_VDSO_SUPPORT 1

#include 

namespace base {

// NOTE: this class may be used from within tcmalloc, and can not
// use any memory allocation routines.
class VDSOSupport {
 public:
  VDSOSupport();

  typedef ElfMemImage::SymbolInfo SymbolInfo;
  typedef ElfMemImage::SymbolIterator SymbolIterator;

  // Answers whether we have a vdso at all.
  bool IsPresent() const { return image_.IsPresent(); }

  // Allow to iterate over all VDSO symbols.
  SymbolIterator begin() const { return image_.begin(); }
  SymbolIterator end() const { return image_.end(); }

  // Look up versioned dynamic symbol in the kernel VDSO.
  // Returns false if VDSO is not present, or doesn't contain given
  // symbol/version/type combination.
  // If info_out != nullptr, additional details are filled in.
  bool LookupSymbol(const char *name, const char *version,
                    int symbol_type, SymbolInfo *info_out) const;

  // Find info about symbol (if any) which overlaps given address.
  // Returns true if symbol was found; false if VDSO isn't present
  // or doesn't have a symbol overlapping given address.
  // If info_out != nullptr, additional details are filled in.
  bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;

  // Used only for testing. Replace real VDSO base with a mock.
  // Returns previous value of vdso_base_. After you are done testing,
  // you are expected to call SetBase() with previous value, in order to
  // reset state to the way it was.
  const void *SetBase(const void *s);

  // Computes vdso_base_ and returns it. Should be called as early as
  // possible; before any thread creation, chroot or setuid.
  static const void *Init();

 private:
  // image_ represents VDSO ELF image in memory.
  // image_.ehdr_ == nullptr implies there is no VDSO.
  ElfMemImage image_;

  // Cached value of auxv AT_SYSINFO_EHDR, computed once.
  // This is a tri-state:
  //   kInvalidBase   => value hasn't been determined yet.
  //              0   => there is no VDSO.
  //           else   => vma of VDSO Elf{32,64}_Ehdr.
  //
  // When testing with mock VDSO, low bit is set.
  // The low bit is always available because vdso_base_ is
  // page-aligned.
  static const void *vdso_base_;

  DISALLOW_COPY_AND_ASSIGN(VDSOSupport);
};

}  // namespace base

#endif  // HAVE_ELF_MEM_IMAGE

#endif  // BASE_VDSO_SUPPORT_H_
gperftools-gperftools-2.18/src/central_freelist.cc000066400000000000000000000311571513545575200224600ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#include "config.h"
#include 
#include "central_freelist.h"
#include "internal_logging.h"  // for ASSERT, MESSAGE
#include "linked_list.h"       // for SLL_Next, SLL_Push, etc
#include "page_heap.h"         // for PageHeap
#include "static_vars.h"       // for Static

#if defined(__has_builtin)
#if __has_builtin(__builtin_add_overflow)
#define USE_ADD_OVERFLOW
#endif
#endif

namespace tcmalloc {

void CentralFreeList::Init(size_t cl) {
  size_class_ = cl;
  tcmalloc::DLL_Init(&empty_);
  tcmalloc::DLL_Init(&nonempty_);
  num_spans_ = 0;
  counter_ = 0;

  max_cache_size_ = kMaxNumTransferEntries;
#ifdef TCMALLOC_SMALL_BUT_SLOW
  // Disable the transfer cache for the small footprint case.
  cache_size_ = 0;
#else
  cache_size_ = 16;
#endif
  if (cl > 0) {
    // Limit the maximum size of the cache based on the size class.  If this
    // is not done, large size class objects will consume a lot of memory if
    // they just sit in the transfer cache.
    int32_t bytes = Static::sizemap()->ByteSizeForClass(cl);
    int32_t objs_to_move = Static::sizemap()->num_objects_to_move(cl);

    ASSERT(objs_to_move > 0 && bytes > 0);
    // Limit each size class cache to at most 1MB of objects or one entry,
    // whichever is greater. Total transfer cache memory used across all
    // size classes then can't be greater than approximately
    // 1MB * kMaxNumTransferEntries.
    max_cache_size_ = std::min(max_cache_size_,
                               std::max(1, (1024 * 1024) / (bytes * objs_to_move)));
    cache_size_ = std::min(cache_size_, max_cache_size_);
  }
  used_slots_ = 0;
  ASSERT(cache_size_ <= max_cache_size_);
}

void CentralFreeList::ReleaseListToSpans(void* start) {
  while (start) {
    void *next = SLL_Next(start);
    ReleaseToSpans(start);
    start = next;
  }
}

void CentralFreeList::ReleaseToSpans(void* object) {
  const PageID p = reinterpret_cast(object) >> kPageShift;
  Span* span = Static::pageheap()->GetDescriptor(p);
  ASSERT(span != nullptr);
  ASSERT(span->refcount > 0);

  // If span is empty, move it to non-empty list
  if (span->objects == nullptr) {
    tcmalloc::DLL_Remove(span);
    tcmalloc::DLL_Prepend(&nonempty_, span);
  }

  // The following check is expensive, so it is disabled by default
  if (false) {
    // Check that object does not occur in list
    int got = 0;
    for (void* p = span->objects; p != nullptr; p = *((void**) p)) {
      ASSERT(p != object);
      got++;
    }
    (void)got;
    ASSERT(got + span->refcount ==
           (span->length<ByteSizeForClass(span->sizeclass));
  }

  counter_++;
  span->refcount--;
  if (span->refcount == 0) {
    counter_ -= ((span->length<ByteSizeForClass(span->sizeclass));
    tcmalloc::DLL_Remove(span);
    --num_spans_;

    // Release central list lock while operating on pageheap
    lock_.Unlock();
    Static::pageheap()->Delete(span);
    lock_.Lock();
  } else {
    *(reinterpret_cast(object)) = span->objects;
    span->objects = object;
  }
}

bool CentralFreeList::EvictRandomSizeClass(
    int locked_size_class, bool force) {
  static int race_counter = 0;
  int t = race_counter++;  // Updated without a lock, but who cares.
  if (t >= Static::num_size_classes()) {
    while (t >= Static::num_size_classes()) {
      t -= Static::num_size_classes();
    }
    race_counter = t;
  }
  ASSERT(t >= 0);
  ASSERT(t < Static::num_size_classes());
  if (t == locked_size_class) return false;
  return Static::central_cache()[t].ShrinkCache(locked_size_class, force);
}

bool CentralFreeList::MakeCacheSpace() {
  // Is there room in the cache?
  if (used_slots_ < cache_size_) return true;
  // Check if we can expand this cache?
  if (cache_size_ == max_cache_size_) return false;
  // Ok, we'll try to grab an entry from some other size class.
  if (EvictRandomSizeClass(size_class_, false) ||
      EvictRandomSizeClass(size_class_, true)) {
    // Succeeded in evicting, we're going to make our cache larger.
    // However, we may have dropped and re-acquired the lock in
    // EvictRandomSizeClass (via ShrinkCache and the LockInverter), so the
    // cache_size may have changed.  Therefore, check and verify that it is
    // still OK to increase the cache_size.
    if (cache_size_ < max_cache_size_) {
      cache_size_++;
      return true;
    }
  }
  return false;
}


namespace {
class LockInverter {
 private:
  SpinLock *held_, *temp_;
 public:
  inline explicit LockInverter(SpinLock* held, SpinLock *temp)
    : held_(held), temp_(temp) { held_->Unlock(); temp_->Lock(); }
  inline ~LockInverter() { temp_->Unlock(); held_->Lock();  }
};
}

// This function is marked as NO_THREAD_SAFETY_ANALYSIS because it uses
// LockInverter to release one lock and acquire another in scoped-lock
// style, which our current annotation/analysis does not support.
bool CentralFreeList::ShrinkCache(int locked_size_class, bool force)
    NO_THREAD_SAFETY_ANALYSIS {
  // Start with a quick check without taking a lock.
  if (cache_size_ == 0) return false;
  // We don't evict from a full cache unless we are 'forcing'.
  if (force == false && used_slots_ == cache_size_) return false;

  // Grab lock, but first release the other lock held by this thread.  We use
  // the lock inverter to ensure that we never hold two size class locks
  // concurrently.  That can create a deadlock because there is no well
  // defined nesting order.
  LockInverter li(&Static::central_cache()[locked_size_class].lock_, &lock_);
  ASSERT(used_slots_ <= cache_size_);
  ASSERT(0 <= cache_size_);
  if (cache_size_ == 0) return false;
  if (used_slots_ == cache_size_) {
    if (force == false) return false;
    // ReleaseListToSpans releases the lock, so we have to make all the
    // updates to the central list before calling it.
    cache_size_--;
    used_slots_--;
    ReleaseListToSpans(tc_slots_[used_slots_].head);
    return true;
  }
  cache_size_--;
  return true;
}

void CentralFreeList::InsertRange(void *start, void *end, int N) {
  SpinLockHolder h(&lock_);
  if (N == Static::sizemap()->num_objects_to_move(size_class_) &&
    MakeCacheSpace()) {
    int slot = used_slots_++;
    ASSERT(slot >=0);
    ASSERT(slot < max_cache_size_);
    TCEntry *entry = &tc_slots_[slot];
    entry->head = start;
    entry->tail = end;
    return;
  }
  ReleaseListToSpans(start);
}

int CentralFreeList::RemoveRange(void **start, void **end, int N) {
  ASSERT(N > 0);
  lock_.Lock();
  if (N == Static::sizemap()->num_objects_to_move(size_class_) &&
      used_slots_ > 0) {
    int slot = --used_slots_;
    ASSERT(slot >= 0);
    TCEntry *entry = &tc_slots_[slot];
    *start = entry->head;
    *end = entry->tail;
    lock_.Unlock();
    return N;
  }

  int result = 0;
  *start = nullptr;
  *end = nullptr;
  // TODO: Prefetch multiple TCEntries?
  result = FetchFromOneSpansSafe(N, start, end);
  if (result != 0) {
    while (result < N) {
      int n;
      void* head = nullptr;
      void* tail = nullptr;
      n = FetchFromOneSpans(N - result, &head, &tail);
      if (!n) break;
      result += n;
      SLL_PushRange(start, head, tail);
    }
  }
  lock_.Unlock();
  return result;
}


int CentralFreeList::FetchFromOneSpansSafe(int N, void **start, void **end) {
  int result = FetchFromOneSpans(N, start, end);
  if (!result) {
    Populate();
    result = FetchFromOneSpans(N, start, end);
  }
  return result;
}

int CentralFreeList::FetchFromOneSpans(int N, void **start, void **end) {
  if (tcmalloc::DLL_IsEmpty(&nonempty_)) return 0;
  Span* span = nonempty_.next;

  ASSERT(span->objects != nullptr);

  int result = 0;
  void *prev, *curr;
  curr = span->objects;
  do {
    prev = curr;
    curr = *(reinterpret_cast(curr));
  } while (++result < N && curr != nullptr);

  if (curr == nullptr) {
    // Move to empty list
    tcmalloc::DLL_Remove(span);
    tcmalloc::DLL_Prepend(&empty_, span);
  }

  *start = span->objects;
  *end = prev;
  span->objects = curr;
  SLL_SetNext(*end, nullptr);
  span->refcount += result;
  counter_ -= result;
  return result;
}

// Fetch memory from the system and add to the central cache freelist.
void CentralFreeList::Populate() {
  // Release central list lock while operating on pageheap
  lock_.Unlock();
  const size_t npages = Static::sizemap()->class_to_pages(size_class_);

  Span* span = Static::pageheap()->NewWithSizeClass(npages, size_class_);
  if (span == nullptr) {
    Log(kLog, __FILE__, __LINE__,
        "tcmalloc: allocation failed", npages << kPageShift);
    lock_.Lock();
    return;
  }
  ASSERT(span->length == npages);
  // Cache sizeclass info eagerly.  Locking is not necessary.
  // (Instead of being eager, we could just replace any stale info
  // about this span, but that seems to be no better in practice.)
  for (int i = 0; i < npages; i++) {
    Static::pageheap()->SetCachedSizeClass(span->start + i, size_class_);
  }

  // Split the block into pieces and add to the free-list
  // TODO: coloring of objects to avoid cache conflicts?
  void** tail = &span->objects;
  char* ptr = reinterpret_cast(span->start << kPageShift);
  char* limit = ptr + (npages << kPageShift);
  const size_t size = Static::sizemap()->ByteSizeForClass(size_class_);
  int num = 0;

  // Note, when ptr is close to the top of address space, ptr + size
  // might overflow the top of address space before we're able to
  // detect that it exceeded limit. So we need to be careful. See
  // https://github.com/gperftools/gperftools/issues/1323.
  ASSERT(limit - size >= ptr);
  for (;;) {

#ifndef USE_ADD_OVERFLOW
    auto nextptr = reinterpret_cast(reinterpret_cast(ptr) + size);
    if (nextptr < ptr || nextptr > limit) {
      break;
    }
#else
    // Same as above, just helping compiler a bit to produce better code
    uintptr_t nextaddr;
    if (__builtin_add_overflow(reinterpret_cast(ptr), size, &nextaddr)) {
      break;
    }
    char* nextptr = reinterpret_cast(nextaddr);
    if (nextptr > limit) {
      break;
    }
#endif

    // [ptr, ptr+size) bytes are all valid bytes, so append them
    *tail = ptr;
    tail = reinterpret_cast(ptr);
    num++;
    ptr = nextptr;
  }
  ASSERT(ptr <= limit);
  ASSERT(ptr > limit - size); // same as ptr + size > limit but avoiding overflow
  *tail = nullptr;
  span->refcount = 0; // No sub-object in use yet

  // Add span to list of non-empty spans
  lock_.Lock();
  tcmalloc::DLL_Prepend(&nonempty_, span);
  ++num_spans_;
  counter_ += num;
}

int CentralFreeList::tc_length() {
  SpinLockHolder h(&lock_);
  return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_);
}

size_t CentralFreeList::OverheadBytes() {
  SpinLockHolder h(&lock_);
  if (size_class_ == 0) {  // 0 holds the 0-sized allocations
    return 0;
  }
  const size_t pages_per_span = Static::sizemap()->class_to_pages(size_class_);
  const size_t object_size = Static::sizemap()->class_to_size(size_class_);
  ASSERT(object_size > 0);
  const size_t overhead_per_span = (pages_per_span * kPageSize) % object_size;
  return num_spans_ * overhead_per_span;
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/central_freelist.h000066400000000000000000000166411513545575200223230ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#ifndef TCMALLOC_CENTRAL_FREELIST_H_
#define TCMALLOC_CENTRAL_FREELIST_H_

#include "config.h"
#include 
#include 
#include "base/spinlock.h"
#include "base/thread_annotations.h"
#include "span.h"

namespace tcmalloc {

// Data kept per size-class in central cache.
class CACHELINE_ALIGNED CentralFreeList {
 public:
  constexpr CentralFreeList() {}

  void Init(size_t cl);

  // These methods all do internal locking.

  // Insert the specified range into the central freelist.  N is the number of
  // elements in the range.  RemoveRange() is the opposite operation.
  void InsertRange(void *start, void *end, int N);

  // Returns the actual number of fetched elements and sets *start and *end.
  int RemoveRange(void **start, void **end, int N);

  // Returns the number of free objects in cache.
  int length() {
    SpinLockHolder h(&lock_);
    return counter_;
  }

  // Returns the number of free objects in the transfer cache.
  int tc_length();

  // Returns the memory overhead (internal fragmentation) attributable
  // to the freelist.  This is memory lost when the size of elements
  // in a freelist doesn't exactly divide the page-size (an 8192-byte
  // page full of 5-byte objects would have 2 bytes memory overhead).
  size_t OverheadBytes();

  // Lock/Unlock the internal SpinLock. Used on the pthread_atfork call
  // to set the lock in a consistent state before the fork.
  void Lock() EXCLUSIVE_LOCK_FUNCTION(lock_) {
    lock_.Lock();
  }

  void Unlock() UNLOCK_FUNCTION(lock_) {
    lock_.Unlock();
  }

 private:
  // TransferCache is used to cache transfers of
  // sizemap.num_objects_to_move(size_class) back and forth between
  // thread caches and the central cache for a given size class.
  struct TCEntry {
    constexpr TCEntry() {}
    void *head{};  // Head of chain of objects.
    void *tail{};  // Tail of chain of objects.
  };

  // A central cache freelist can have anywhere from 0 to kMaxNumTransferEntries
  // slots to put link list chains into.
#ifdef TCMALLOC_SMALL_BUT_SLOW
  // For the small memory model, the transfer cache is not used.
  static const int kMaxNumTransferEntries = 0;
#else
  // Starting point for the the maximum number of entries in the transfer cache.
  // This actual maximum for a given size class may be lower than this
  // maximum value.
  static const int kMaxNumTransferEntries = 64;
#endif

  // REQUIRES: lock_ is held
  // Remove object from cache and return.
  // Return nullptr if no free entries in cache.
  int FetchFromOneSpans(int N, void **start, void **end) EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // REQUIRES: lock_ is held
  // Remove object from cache and return.  Fetches
  // from pageheap if cache is empty.  Only returns
  // nullptr on allocation failure.
  int FetchFromOneSpansSafe(int N, void **start, void **end) EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // REQUIRES: lock_ is held
  // Release a linked list of objects to spans.
  // May temporarily release lock_.
  void ReleaseListToSpans(void *start) EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // REQUIRES: lock_ is held
  // Release an object to spans.
  // May temporarily release lock_.
  void ReleaseToSpans(void* object) EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // REQUIRES: lock_ is held
  // Populate cache by fetching from the page heap.
  // May temporarily release lock_.
  void Populate() EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // REQUIRES: lock is held.
  // Tries to make room for a TCEntry.  If the cache is full it will try to
  // expand it at the cost of some other cache size.  Return false if there is
  // no space.
  bool MakeCacheSpace() EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // REQUIRES: lock_ for locked_size_class is held.
  // Picks a "random" size class to steal TCEntry slot from.  In reality it
  // just iterates over the sizeclasses but does so without taking a lock.
  // Returns true on success.
  // May temporarily lock a "random" size class.
  static bool EvictRandomSizeClass(int locked_size_class, bool force);

  // REQUIRES: lock_ is *not* held.
  // Tries to shrink the Cache.  If force is true it will relase objects to
  // spans if it allows it to shrink the cache.  Return false if it failed to
  // shrink the cache.  Decrements cache_size_ on succeess.
  // May temporarily take lock_.  If it takes lock_, the locked_size_class
  // lock is released to keep the thread from holding two size class locks
  // concurrently which could lead to a deadlock.
  bool ShrinkCache(int locked_size_class, bool force) LOCKS_EXCLUDED(lock_);

  // This lock protects all the data members.  cached_entries and cache_size_
  // may be looked at without holding the lock.
  SpinLock lock_;

  // We keep linked lists of empty and non-empty spans.
  size_t   size_class_{};   // My size class
  Span     empty_;          // Dummy header for list of empty spans
  Span     nonempty_;       // Dummy header for list of non-empty spans
  size_t   num_spans_{};    // Number of spans in empty_ plus nonempty_
  size_t   counter_{};      // Number of free objects in cache entry

  // Here we reserve space for TCEntry cache slots.  Space is preallocated
  // for the largest possible number of entries than any one size class may
  // accumulate.  Not all size classes are allowed to accumulate
  // kMaxNumTransferEntries, so there is some wasted space for those size
  // classes.
  TCEntry tc_slots_[kMaxNumTransferEntries];

  // Number of currently used cached entries in tc_slots_.  This variable is
  // updated under a lock but can be read without one.
  int32_t used_slots_{};
  // The current number of slots for this size class.  This is an
  // adaptive value that is increased if there is lots of traffic
  // on a given size class.
  int32_t cache_size_{};
  // Maximum size of the cache for a given size class.
  int32_t max_cache_size_{};
};

}  // namespace tcmalloc

#endif  // TCMALLOC_CENTRAL_FREELIST_H_
gperftools-gperftools-2.18/src/check_address-inl.h000066400000000000000000000152431513545575200223350ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2023, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// This is internal implementation details of
// stacktrace_generic_fp-inl.h module. We only split this into
// separate header to enable unit test coverage.

#include "config.h"

// This is only used on OS-es with mmap support.
#include 
#include 
#include 
#include 
#include 
#include 

#if HAVE_SYS_SYSCALL_H && !__APPLE__
#include 
#endif

#include "base/logging.h"

namespace {

#if defined(__linux__) && !defined(FORCE_PIPES)
#define CHECK_ADDRESS_USES_SIGPROCMASK

// Linux kernel ABI for sigprocmask requires us to pass exact sizeof
// for kernel's sigset_t. Which is 64-bit for most arches, with only
// notable exception of mips.
#if defined(__mips__)
static constexpr int kKernelSigSetSize = 16;
#else
static constexpr int kKernelSigSetSize = 8;
#endif

// For Linux we have two strategies. One is calling sigprocmask with
// bogus HOW argument and 'new' sigset arg our address. Kernel ends up
// reading new sigset before interpreting how. So then we either get
// EFAULT when addr is unreadable, or we get EINVAL for readable addr,
// but bogus HOW argument.
//
// We 'steal' this idea from abseil. But nothing guarantees this exact
// behavior of Linux. So to be future-compatible (some our binaries
// will run tens of years from the time they're compiled), we also
// have second more robust method.
bool CheckAccessSingleSyscall(uintptr_t addr, int pagesize) {
  addr &= ~uintptr_t{15};

  if (addr == 0) {
    return false;
  }

  int rv = syscall(SYS_rt_sigprocmask, ~0, addr, uintptr_t{0}, kKernelSigSetSize);
  RAW_CHECK(rv < 0, "sigprocmask(~0, addr, ...)");

  return (errno != EFAULT);
}

// This is second strategy. Idea is more or less same as before, but
// we use SIG_BLOCK for HOW argument. Then if this succeeds (with side
// effect of blocking random set of signals), we simply restore
// previous signal mask.
bool CheckAccessTwoSyscalls(uintptr_t addr, int pagesize) {
  addr &= ~uintptr_t{15};

  if (addr == 0) {
    return false;
  }

  uintptr_t old[(kKernelSigSetSize + sizeof(uintptr_t) - 1) / sizeof(uintptr_t)];
  int rv = syscall(SYS_rt_sigprocmask, SIG_BLOCK, addr, old, kKernelSigSetSize);
  if (rv  == 0) {
    syscall(SYS_rt_sigprocmask, SIG_SETMASK, old, nullptr, kKernelSigSetSize);
    return true;
  }
  return false;
}

bool CheckAddressFirstCall(uintptr_t addr, int pagesize);

bool (* volatile CheckAddress)(uintptr_t addr, int pagesize) = CheckAddressFirstCall;

// And we choose between strategies by checking at runtime if
// single-syscall approach actually works and switch to a proper
// version.
bool CheckAddressFirstCall(uintptr_t addr, int pagesize) {
  // Note, mmap call below might recurse into backtrace via heap
  // checker (mmap "profiler"). So lets make things safe for recursion
  // first.
  CheckAddress = CheckAccessTwoSyscalls;

  void* unreadable = mmap(0, pagesize, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  RAW_CHECK(unreadable != MAP_FAILED, "mmap of unreadable");

  if (!CheckAccessSingleSyscall(reinterpret_cast(unreadable), pagesize)) {
    CheckAddress = CheckAccessSingleSyscall;
  }

  // Sanity check that our unreadable address is unreadable and that
  // our readable address (our own fn pointer variable) is readable.
  RAW_CHECK(CheckAddress(reinterpret_cast(CheckAddress),
                         pagesize),
            "sanity check for readable addr");
  RAW_CHECK(!CheckAddress(reinterpret_cast(unreadable),
                          pagesize),
            "sanity check for unreadable addr");

  (void)munmap(unreadable, pagesize);

  return CheckAddress(addr, pagesize);
};

#else

#if HAVE_SYS_SYSCALL_H && !__APPLE__
static int raw_read(int fd, void* buf, size_t count) {
  return syscall(SYS_read, fd, buf, count);
}
static int raw_write(int fd, void* buf, size_t count) {
  return syscall(SYS_write, fd, buf, count);
}
#else
#define raw_read read
#define raw_write write
#endif

bool CheckAddress(uintptr_t addr, int pagesize) {
  static tcmalloc::TrivialOnce once;
  static int fds[2];

  once.RunOnce([] () {
    RAW_CHECK(pipe(fds) == 0, "pipe(fds)");

    auto add_flag = [] (int fd, int get, int set, int the_flag) {
      int flags = fcntl(fd, get, 0);
      RAW_CHECK(flags >= 0, "fcntl get");
      flags |= the_flag;
      RAW_CHECK(fcntl(fd, set, flags) == 0, "fcntl set");
    };

    for (int i = 0; i < 2; i++) {
      add_flag(fds[i], F_GETFD, F_SETFD, FD_CLOEXEC);
      add_flag(fds[i], F_GETFL, F_SETFL, O_NONBLOCK);
    }
  });

  do {
    int rv = raw_write(fds[1], reinterpret_cast(addr), 1);
    RAW_CHECK(rv != 0, "raw_write(...) == 0");
    if (rv > 0) {
      return true;
    }
    if (errno == EFAULT) {
      return false;
    }

    RAW_CHECK(errno == EAGAIN, "write errno must be EAGAIN");

    char drainbuf[256];
    do {
      rv = raw_read(fds[0], drainbuf, sizeof(drainbuf));
      if (rv < 0 && errno != EINTR) {
        RAW_CHECK(errno == EAGAIN, "read errno must be EAGAIN");
        break;
      }
      // read succeeded or we got EINTR
    } while (true);
  } while (true);

  return false;
}

#endif

}  // namespace
gperftools-gperftools-2.18/src/common.cc000066400000000000000000000270261513545575200204230ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#include "config.h"

#include  // for strtol
#ifdef HAVE_UNISTD_H
#include 
#endif

#include 

#include "common.h"
#include "system-alloc.h"
#include "base/spinlock.h"
#include "base/commandlineflags.h"
#include "getenv_safe.h" // TCMallocGetenvSafe

namespace tcmalloc {

// Define the maximum number of object per classe type to transfer between
// thread and central caches.
static int32_t FLAGS_tcmalloc_transfer_num_objects;

static constexpr int32_t kDefaultTransferNumObjecs = 32;

// The init function is provided to explicit initialize the variable value
// from the env. var to avoid C++ global construction that might defer its
// initialization after a malloc/new call.
static inline void InitTCMallocTransferNumObjects()
{
  if (FLAGS_tcmalloc_transfer_num_objects == 0) {
    const char *envval = TCMallocGetenvSafe("TCMALLOC_TRANSFER_NUM_OBJ");
    FLAGS_tcmalloc_transfer_num_objects = !envval ? kDefaultTransferNumObjecs :
      strtol(envval, nullptr, 10);
  }
}

// Note: the following only works for "n"s that fit in 32-bits, but
// that is fine since we only use it for small sizes.
static inline int LgFloor(size_t n) {
  int log = 0;
  for (int i = 4; i >= 0; --i) {
    int shift = (1 << i);
    size_t x = n >> shift;
    if (x != 0) {
      n = x;
      log += shift;
    }
  }
  ASSERT(n == 1);
  return log;
}

static int AlignmentForSize(size_t size) {
  int alignment = kAlignment;
  if (size > kMaxSize) {
    // Cap alignment at kPageSize for large sizes.
    alignment = kPageSize;
  } else if (size >= 128) {
    // Space wasted due to alignment is at most 1/8, i.e., 12.5%.
    alignment = (1 << LgFloor(size)) / 8;
  } else if (size >= kMinAlign) {
    // We need an alignment of at least 16 bytes to satisfy
    // requirements for some SSE types.
    alignment = kMinAlign;
  }
  // Maximum alignment allowed is page size alignment.
  if (alignment > kPageSize) {
    alignment = kPageSize;
  }
  CHECK_CONDITION(size < kMinAlign || alignment >= kMinAlign);
  CHECK_CONDITION((alignment & (alignment - 1)) == 0);
  return alignment;
}

int SizeMap::NumMoveSize(size_t size) {
  if (size == 0) return 0;
  // Use approx 64k transfers between thread and central caches.
  int num = static_cast(64.0 * 1024.0 / size);
  if (num < 2) num = 2;

  // Avoid bringing too many objects into small object free lists.
  // If this value is too large:
  // - We waste memory with extra objects sitting in the thread caches.
  // - The central freelist holds its lock for too long while
  //   building a linked list of objects, slowing down the allocations
  //   of other threads.
  // If this value is too small:
  // - We go to the central freelist too often and we have to acquire
  //   its lock each time.
  // This value strikes a balance between the constraints above.
  if (num > FLAGS_tcmalloc_transfer_num_objects)
    num = FLAGS_tcmalloc_transfer_num_objects;

  return num;
}

// Initialize the mapping arrays
void SizeMap::Init() {
  InitTCMallocTransferNumObjects();

#if (!defined(_WIN32) || defined(TCMALLOC_BRAVE_EFFECTIVE_PAGE_SIZE)) && !defined(TCMALLOC_COWARD_EFFECTIVE_PAGE_SIZE)
  size_t native_page_size = tcmalloc::commandlineflags::StringToLongLong(
    TCMallocGetenvSafe("TCMALLOC_OVERRIDE_PAGESIZE"), getpagesize());
#else
  // So windows getpagesize() returns 64k. Because that is
  // "granularity size" w.r.t. their virtual memory facility. So kinda
  // maybe not a bad idea to also have effective logical pages at 64k
  // too. But it breaks frag_unittest (for mostly harmless
  // reason). And I am not brave enough to have our behavior change so
  // much on windows (which isn't that much; people routinely run 256k
  // logical pages anyways).
  constexpr size_t native_page_size = kPageSize;
#endif

  size_t min_span_size = std::max(native_page_size, kPageSize);
  if (min_span_size > kPageSize && (min_span_size % kPageSize) != 0) {
    Log(kLog, __FILE__, __LINE__, "This should never happen, but somehow "
        "we got systems page size not power of 2 and not multiple of "
        "malloc's logical page size. Releasing memory back will mostly not happen. "
        "system: ", native_page_size, ", malloc: ", kPageSize);
    min_span_size = kPageSize;
  }

  min_span_size_in_pages_ = min_span_size / kPageSize;

  // Do some sanity checking on add_amount[]/shift_amount[]/class_array[]
  if (ClassIndex(0) != 0) {
    Log(kCrash, __FILE__, __LINE__,
        "Invalid class index for size 0", ClassIndex(0));
  }
  if (ClassIndex(kMaxSize) >= sizeof(class_array_)) {
    Log(kCrash, __FILE__, __LINE__,
        "Invalid class index for kMaxSize", ClassIndex(kMaxSize));
  }

  // Compute the size classes we want to use
  int sc = 1;   // Next size class to assign
  int alignment = kAlignment;
  CHECK_CONDITION(kAlignment <= kMinAlign);
  for (size_t size = kAlignment; size <= kMaxSize; size += alignment) {
    alignment = AlignmentForSize(size);
    CHECK_CONDITION((size % alignment) == 0);

    int blocks_to_move = NumMoveSize(size) / 4;
    size_t psize = 0;
    do {
      psize += min_span_size;
      // Allocate enough pages so leftover is less than 1/8 of total.
      // This bounds wasted space to at most 12.5%.
      while ((psize % size) > (psize >> 3)) {
        psize += min_span_size;
      }
      // Continue to add pages until there are at least as many objects in
      // the span as are needed when moving objects from the central
      // freelists and spans to the thread caches.
    } while ((psize / size) < (blocks_to_move));
    const size_t my_pages = psize >> kPageShift;

    if (sc > 1 && my_pages == class_to_pages_[sc-1]) {
      // See if we can merge this into the previous class without
      // increasing the fragmentation of the previous class.
      const size_t my_objects = (my_pages << kPageShift) / size;
      const size_t prev_objects = (class_to_pages_[sc-1] << kPageShift)
                                  / class_to_size_[sc-1];
      if (my_objects == prev_objects) {
        // Adjust last class to include this size
        class_to_size_[sc-1] = size;
        continue;
      }
    }

    // Add new class
    class_to_pages_[sc] = my_pages;
    class_to_size_[sc] = size;
    sc++;
  }
  num_size_classes = sc;
  if (sc > kClassSizesMax) {
    Log(kCrash, __FILE__, __LINE__,
        "too many size classes: (found vs. max)", sc, kClassSizesMax);
  }

  // Initialize the mapping arrays
  int next_size = 0;
  for (int c = 1; c < num_size_classes; c++) {
    const int max_size_in_class = class_to_size_[c];
    for (int s = next_size; s <= max_size_in_class; s += kAlignment) {
      class_array_[ClassIndex(s)] = c;
    }
    next_size = max_size_in_class + kAlignment;
  }

  // Double-check sizes just to be safe
  for (size_t size = 0; size <= kMaxSize;) {
    const int sc = SizeClass(size);
    if (sc <= 0 || sc >= num_size_classes) {
      Log(kCrash, __FILE__, __LINE__,
          "Bad size class (class, size)", sc, size);
    }
    if (sc > 1 && size <= class_to_size_[sc-1]) {
      Log(kCrash, __FILE__, __LINE__,
          "Allocating unnecessarily large class (class, size)", sc, size);
    }
    const size_t s = class_to_size_[sc];
    if (size > s || s == 0) {
      Log(kCrash, __FILE__, __LINE__,
          "Bad (class, size, requested)", sc, s, size);
    }
    if (size <= kMaxSmallSize) {
      size += 8;
    } else {
      size += 128;
    }
  }

  // Our fast-path aligned allocation functions rely on 'naturally
  // aligned' sizes to produce aligned addresses. Lets check if that
  // holds for size classes that we produced.
  //
  // I.e. we're checking that
  //
  // align = (1 << shift), malloc(i * align) % align == 0,
  //
  // for all align values up to kPageSize.
  for (size_t align = kMinAlign; align <= kPageSize; align <<= 1) {
    for (size_t size = align; size < kPageSize; size += align) {
      CHECK_CONDITION(class_to_size_[SizeClass(size)] % align == 0);
    }
  }

  // Initialize the num_objects_to_move array.
  for (size_t cl = 1; cl  < num_size_classes; ++cl) {
    num_objects_to_move_[cl] = NumMoveSize(ByteSizeForClass(cl));
  }
}

// Metadata allocator -- keeps stats about how many bytes allocated.
static uint64_t metadata_system_bytes_ = 0;
static const size_t kMetadataAllocChunkSize = 8*1024*1024;
// As ThreadCache objects are allocated with MetaDataAlloc, and also
// CACHELINE_ALIGNED, we must use the same alignment as TCMalloc_SystemAlloc.
static const size_t kMetadataAllignment = sizeof(MemoryAligner);

static char *metadata_chunk_alloc_;
static size_t metadata_chunk_avail_;

static SpinLock metadata_alloc_lock;

void* MetaDataAlloc(size_t bytes) {
  if (bytes >= kMetadataAllocChunkSize) {
    void *rv = TCMalloc_SystemAlloc(bytes,
                                    nullptr, kMetadataAllignment);
    if (rv != nullptr) {
      metadata_system_bytes_ += bytes;
    }
    return rv;
  }

  SpinLockHolder h(&metadata_alloc_lock);

  // the following works by essentially turning address to integer of
  // log_2 kMetadataAllignment size and negating it. I.e. negated
  // value + original value gets 0 and that's what we want modulo
  // kMetadataAllignment. Note, we negate before masking higher bits
  // off, otherwise we'd have to mask them off after negation anyways.
  intptr_t alignment = -reinterpret_cast(metadata_chunk_alloc_) & (kMetadataAllignment-1);

  if (metadata_chunk_avail_ < bytes + alignment) {
    size_t real_size;
    void *ptr = TCMalloc_SystemAlloc(kMetadataAllocChunkSize,
                                     &real_size, kMetadataAllignment);
    if (ptr == nullptr) {
      return nullptr;
    }

    metadata_chunk_alloc_ = static_cast(ptr);
    metadata_chunk_avail_ = real_size;

    alignment = 0;
  }

  void *rv = static_cast(metadata_chunk_alloc_ + alignment);
  bytes += alignment;
  metadata_chunk_alloc_ += bytes;
  metadata_chunk_avail_ -= bytes;
  metadata_system_bytes_ += bytes;
  return rv;
}

uint64_t metadata_system_bytes() { return metadata_system_bytes_; }

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/common.h000066400000000000000000000276471513545575200202760ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 
//
// Common definitions for tcmalloc code.

#ifndef TCMALLOC_COMMON_H_
#define TCMALLOC_COMMON_H_

#include "config.h"
#include                      // for size_t
#include                      // for uintptr_t, uint64_t
#include "internal_logging.h"  // for ASSERT, etc
#include "base/basictypes.h"   // for LIKELY, etc

// Type that can hold a page number
typedef uintptr_t PageID;

// Type that can hold the length of a run of pages
typedef uintptr_t Length;

//-------------------------------------------------------------------
// Configuration
//-------------------------------------------------------------------

#if defined(TCMALLOC_ALIGN_8BYTES)
// Unless we force to use 8 bytes alignment we use an alignment of
// at least 16 bytes to statisfy requirements for some SSE types.
// Keep in mind when using the 16 bytes alignment you can have a space
// waste due alignment of 25%. (eg malloc of 24 bytes will get 32 bytes)
static const size_t kMinAlign   = 8;
#else
static const size_t kMinAlign   = 16;
#endif

// Using large pages speeds up the execution at a cost of larger memory use.
// Deallocation may speed up by a factor as the page map gets 8x smaller, so
// lookups in the page map result in fewer L2 cache misses, which translates to
// speedup for application/platform combinations with high L2 cache pressure.
// As the number of size classes increases with large pages, we increase
// the thread cache allowance to avoid passing more free ranges to and from
// central lists.  Also, larger pages are less likely to get freed.
// These two factors cause a bounded increase in memory use.
#if defined(TCMALLOC_PAGE_SIZE_SHIFT)
static const size_t kPageShift  = TCMALLOC_PAGE_SIZE_SHIFT;
#else
static const size_t kPageShift  = 13;
#endif

static const size_t kClassSizesMax = 128;

static const size_t kMaxThreadCacheSize = 4 << 20;

static const size_t kPageSize   = 1 << kPageShift;
static const size_t kMaxSize    = 256 * 1024;
static const size_t kAlignment  = 8;
// For all span-lengths <= kMaxPages we keep an exact-size list in PageHeap.
static const size_t kMaxPages = 1 << (20 - kPageShift);

// Default bound on the total amount of thread caches.
#ifdef TCMALLOC_SMALL_BUT_SLOW
// Make the overall thread cache no bigger than that of a single thread
// for the small memory footprint case.
static const size_t kDefaultOverallThreadCacheSize = kMaxThreadCacheSize;
#else
static const size_t kDefaultOverallThreadCacheSize = 8u * kMaxThreadCacheSize;
#endif

// Lower bound on the per-thread cache sizes
static const size_t kMinThreadCacheSize = kMaxSize * 2;

// The number of bytes one ThreadCache will steal from another when
// the first ThreadCache is forced to Scavenge(), delaying the
// next call to Scavenge for this thread.
static const size_t kStealAmount = 1 << 16;

// The number of times that a deallocation can cause a freelist to
// go over its max_length() before shrinking max_length().
static const int kMaxOverages = 3;

// Maximum length we allow a per-thread free-list to have before we
// move objects from it into the corresponding central free-list.  We
// want this big to avoid locking the central free-list too often.  It
// should not hurt to make this list somewhat big because the
// scavenging code will shrink it down when its contents are not in use.
static const int kMaxDynamicFreeListLength = 8192;

static const Length kMaxValidPages = (~static_cast(0)) >> kPageShift;

#if (__aarch64__ || __x86_64__ || _M_AMD64 || _M_ARM64) && !__sun__
// All current x86_64 processors only look at the lower 48 bits in
// virtual to physical address translation. The top 16 are all same as
// bit 47. And bit 47 value 1 reserved for kernel-space addresses in
// practice. So it is actually 47 usable bits from malloc
// perspective. This lets us use faster two level page maps on this
// architecture.
//
// There is very similar story on 64-bit arms except it has full 48
// bits for user-space. Because of that, and because in principle OSes
// can start giving some of highest-bit-set addresses to user-space,
// we don't bother to limit x86 to 47 bits.
//
// As of now there are published plans to add more bits to x86-64
// virtual address space, but since 48 bits has been norm for long
// time and lots of software is relying on it, it will be opt-in from
// OS perspective. So we can keep doing "48 bits" at least for now.
static const int kAddressBits = (sizeof(void*) < 8 ? (8 * sizeof(void*)) : 48);
#else
// mipsen and ppcs have more general hardware so we have to support
// full 64-bits of addresses.
static const int kAddressBits = 8 * sizeof(void*);
#endif

namespace tcmalloc {

// Convert byte size into pages.  This won't overflow, but may return
// an unreasonably large value if bytes is huge enough.
inline Length pages(size_t bytes) {
  return (bytes >> kPageShift) +
      ((bytes & (kPageSize - 1)) > 0 ? 1 : 0);
}

// Size-class information + mapping
class SizeMap {
 private:
  //-------------------------------------------------------------------
  // Mapping from size to size_class and vice versa
  //-------------------------------------------------------------------

  // Sizes <= 1024 have an alignment >= 8.  So for such sizes we have an
  // array indexed by ceil(size/8).  Sizes > 1024 have an alignment >= 128.
  // So for these larger sizes we have an array indexed by ceil(size/128).
  //
  // We flatten both logical arrays into one physical array and use
  // arithmetic to compute an appropriate index.  The constants used by
  // ClassIndex() were selected to make the flattening work.
  //
  // Examples:
  //   Size       Expression                      Index
  //   -------------------------------------------------------
  //   0          (0 + 7) / 8                     0
  //   1          (1 + 7) / 8                     1
  //   ...
  //   1024       (1024 + 7) / 8                  128
  //   1025       (1025 + 127 + (120<<7)) / 128   129
  //   ...
  //   32768      (32768 + 127 + (120<<7)) / 128  376
  static const int kMaxSmallSize = 1024;
  static const size_t kClassArraySize =
      ((kMaxSize + 127 + (120 << 7)) >> 7) + 1;
  unsigned char class_array_[kClassArraySize];

  static inline size_t SmallSizeClass(size_t s) {
    return (static_cast(s) + 7) >> 3;
  }

  static inline size_t LargeSizeClass(size_t s) {
    return (static_cast(s) + 127 + (120 << 7)) >> 7;
  }

  // If size is no more than kMaxSize, compute index of the
  // class_array[] entry for it, putting the class index in output
  // parameter idx and returning true. Otherwise return false.
  static ALWAYS_INLINE bool ClassIndexMaybe(size_t s,
                                            uint32_t* idx) {
    if (PREDICT_TRUE(s <= kMaxSmallSize)) {
      *idx = (static_cast(s) + 7) >> 3;
      return true;
    } else if (s <= kMaxSize) {
      *idx = (static_cast(s) + 127 + (120 << 7)) >> 7;
      return true;
    }
    return false;
  }

  // Compute index of the class_array[] entry for a given size
  static inline size_t ClassIndex(size_t s) {
    // Use unsigned arithmetic to avoid unnecessary sign extensions.
    ASSERT(0 <= s);
    ASSERT(s <= kMaxSize);
    if (PREDICT_TRUE(s <= kMaxSmallSize)) {
      return SmallSizeClass(s);
    } else {
      return LargeSizeClass(s);
    }
  }

  // Number of objects to move between a per-thread list and a central
  // list in one shot.  We want this to be not too small so we can
  // amortize the lock overhead for accessing the central list.  Making
  // it too big may temporarily cause unnecessary memory wastage in the
  // per-thread free list until the scavenger cleans up the list.
  int num_objects_to_move_[kClassSizesMax];

  int NumMoveSize(size_t size);

  // Mapping from size class to max size storable in that class
  int32_t class_to_size_[kClassSizesMax];

  // Mapping from size class to number of pages to allocate at a time
  size_t class_to_pages_[kClassSizesMax];

  size_t min_span_size_in_pages_;

public:
  size_t num_size_classes;

  // Constructor should do nothing since we rely on explicit Init()
  // call, which may or may not be called before the constructor runs.
  SizeMap() { }

  // Initialize the mapping arrays
  void Init();

  inline int SizeClass(size_t size) {
    return class_array_[ClassIndex(size)];
  }

  // Check if size is small enough to be representable by a size
  // class, and if it is, put matching size class into *cl. Returns
  // true iff matching size class was found.
  ALWAYS_INLINE bool GetSizeClass(size_t size, uint32_t* cl) {
    uint32_t idx;
    if (!ClassIndexMaybe(size, &idx)) {
      return false;
    }
    *cl = class_array_[idx];
    return true;
  }

  // Get the byte-size for a specified class
  ALWAYS_INLINE int32_t ByteSizeForClass(uint32_t cl) {
    return class_to_size_[cl];
  }

  // Mapping from size class to max size storable in that class
  int32_t class_to_size(uint32_t cl) {
    return class_to_size_[cl];
  }

  // Mapping from size class to number of pages to allocate at a time
  size_t class_to_pages(uint32_t cl) {
    return class_to_pages_[cl];
  }

  // Number of objects to move between a per-thread list and a central
  // list in one shot.  We want this to be not too small so we can
  // amortize the lock overhead for accessing the central list.  Making
  // it too big may temporarily cause unnecessary memory wastage in the
  // per-thread free list until the scavenger cleans up the list.
  int num_objects_to_move(uint32_t cl) {
    return num_objects_to_move_[cl];
  }

  // Smallest Span size in bytes (max of system's page size and
  // kPageSize).
  Length min_span_size_in_pages() {
    return min_span_size_in_pages_;
  }
};

// Allocates "bytes" worth of memory and returns it.  Increments
// metadata_system_bytes appropriately.  May return nullptr if
// allocation fails.  Requires pageheap_lock is held.
void* MetaDataAlloc(size_t bytes);

// Returns the total number of bytes allocated from the system.
// Requires pageheap_lock is held.
uint64_t metadata_system_bytes();

// size/depth are made the same size as a pointer so that some generic
// code below can conveniently cast them back and forth to void*.
static const int kMaxStackDepth = 31;
struct StackTrace {
  uintptr_t size;          // Size of object
  uintptr_t depth;         // Number of PC values stored in array below
  void*     stack[kMaxStackDepth];
};

}  // namespace tcmalloc

#endif  // TCMALLOC_COMMON_H_
gperftools-gperftools-2.18/src/config_for_unittests.h000066400000000000000000000075711513545575200232350ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// All Rights Reserved.
//
// Author: Craig Silverstein
//
// This file is needed for windows -- unittests are not part of the
// perftools dll, but still want to include config.h just like the
// dll does, so they can use internal tools and APIs for testing.
//
// The problem is that config.h declares PERFTOOLS_DLL_DECL to be
// for exporting symbols, but the unittest needs to *import* symbols
// (since it's not the dll).
//
// The solution is to have this file, which is just like config.h but
// sets PERFTOOLS_DLL_DECL to do a dllimport instead of a dllexport.
//
// The reason we need this extra PERFTOOLS_DLL_DECL_FOR_UNITTESTS
// variable is in case people want to set PERFTOOLS_DLL_DECL explicitly
// to something other than __declspec(dllexport).  In that case, they
// may want to use something other than __declspec(dllimport) for the
// unittest case.  For that, we allow folks to define both
// PERFTOOLS_DLL_DECL and PERFTOOLS_DLL_DECL_FOR_UNITTESTS explicitly.
//
// NOTE: This file is equivalent to config.h on non-windows systems,
// which never defined PERFTOOLS_DLL_DECL_FOR_UNITTESTS and always
// define PERFTOOLS_DLL_DECL to the empty string.

#include "config.h"

#undef PERFTOOLS_DLL_DECL
#ifdef PERFTOOLS_DLL_DECL_FOR_UNITTESTS
# define PERFTOOLS_DLL_DECL  PERFTOOLS_DLL_DECL_FOR_UNITTESTS
#else
# define PERFTOOLS_DLL_DECL  // if DLL_DECL_FOR_UNITTESTS isn't defined, use ""
#endif

#if defined(__clang__)
#if __has_warning("-Wuse-after-free")
#pragma clang diagnostic ignored "-Wuse-after-free"
#endif
#if __has_warning("-Wunused-result")
#pragma clang diagnostic ignored "-Wunused-result"
#endif
#if __has_warning("-Wunused-private-field")
#pragma clang diagnostic ignored "-Wunused-private-field"
#endif
#if __has_warning("-Wimplicit-exception-spec-mismatch")
#pragma clang diagnostic ignored "-Wimplicit-exception-spec-mismatch"
#endif
#if __has_warning("-Wmissing-exception-spec")
#pragma clang diagnostic ignored "-Wmissing-exception-spec"
#endif
#if __has_warning("-Wunused-const-variable")
#pragma clang diagnostic ignored "-Wunused-const-variable"
#endif
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wuse-after-free"
#pragma GCC diagnostic ignored "-Wunused-result"
#endif
gperftools-gperftools-2.18/src/debugallocation.cc000066400000000000000000001626731513545575200222770ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2000, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Urs Holzle 

#include "config.h"
#include 
#ifdef HAVE_FCNTL_H
#include 
#endif
#include 
// We only need malloc.h for structs mallinfo and mallinfo2.
#if defined(HAVE_STRUCT_MALLINFO) || defined(HAVE_STRUCT_MALLINFO2)
// Malloc can be in several places on older versions of OS X.
# if defined(HAVE_MALLOC_H)
# include 
# elif defined(HAVE_MALLOC_MALLOC_H)
# include 
# elif defined(HAVE_SYS_MALLOC_H)
# include 
# endif
#endif
#include 
#include 
#include 
#ifdef HAVE_MMAP
#include 
#endif
#include 
#include 
#ifdef HAVE_UNISTD_H
#include 
#endif

#include 
#include 

// Will be pulled in as along with tcmalloc.cc
// #include 

#include "addressmap-inl.h"
#include "base/commandlineflags.h"
#include "base/googleinit.h"
#include "base/logging.h"
#include "base/spinlock.h"
#include "base/static_storage.h"
#include "base/threading.h"
#include "malloc_backtrace.h"
#include "malloc_hook-inl.h"
#include "maybe_emergency_malloc.h" // IWYU pragma: keep
#include "safe_strerror.h"
#include "symbolize.h"

// NOTE: due to #define below, tcmalloc.cc will omit tc_XXX
// definitions. So that debug implementations can be defined
// instead. We're going to use do_malloc, do_free and other do_XXX
// functions that are defined in tcmalloc.cc for actual memory
// management
#define TCMALLOC_USING_DEBUGALLOCATION
#include "tcmalloc.cc"

// __THROW is defined in glibc systems.  It means, counter-intuitively,
// "This function will never throw an exception."  It's an optional
// optimization tool, but we may need to use it to match glibc prototypes.
#ifndef __THROW    // I guess we're not on a glibc system
# define __THROW   // __THROW is just an optimization, so ok to make it ""
#endif

// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
// form of the name instead.
#ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
#endif

// ========================================================================= //

DEFINE_bool(malloctrace,
            EnvToBool("TCMALLOC_TRACE", false),
            "Enables memory (de)allocation tracing to /tmp/google.alloc.");
#ifdef HAVE_MMAP
DEFINE_bool(malloc_page_fence,
            EnvToBool("TCMALLOC_PAGE_FENCE", false),
            "Enables putting of memory allocations at page boundaries "
            "with a guard page following the allocation (to catch buffer "
            "overruns right when they happen).");
DEFINE_bool(malloc_page_fence_never_reclaim,
            EnvToBool("TCMALLOC_PAGE_FENCE_NEVER_RECLAIM", false),
            "Enables making the virtual address space inaccessible "
            "upon a deallocation instead of returning it and reusing later.");
DEFINE_bool(malloc_page_fence_readable,
            EnvToBool("TCMALLOC_PAGE_FENCE_READABLE", false),
            "Permits reads to the page fence.");
#else
DEFINE_bool(malloc_page_fence, false, "Not usable (requires mmap)");
DEFINE_bool(malloc_page_fence_never_reclaim, false, "Not usable (required mmap)");
#endif
DEFINE_bool(malloc_reclaim_memory,
            EnvToBool("TCMALLOC_RECLAIM_MEMORY", true),
            "If set to false, we never return memory to malloc "
            "when an object is deallocated. This ensures that all "
            "heap object addresses are unique.");
DEFINE_int32(max_free_queue_size,
             EnvToInt("TCMALLOC_MAX_FREE_QUEUE_SIZE", 10*1024*1024),
             "If greater than 0, keep freed blocks in a queue instead of "
             "releasing them to the allocator immediately.  Release them when "
             "the total size of all blocks in the queue would otherwise exceed "
             "this limit.");

DEFINE_bool(symbolize_stacktrace,
            EnvToBool("TCMALLOC_SYMBOLIZE_STACKTRACE", true),
            "Symbolize the stack trace when provided (on some error exits)");

// ========================================================================= //

// A safe version of printf() that does not do any allocation and
// uses very little stack space.
static void TracePrintf(int fd, const char *fmt, ...)
  __attribute__ ((__format__ (__printf__, 2, 3)));

// Round "value" up to next "alignment" boundary.
// Requires that "alignment" be a power of two.
static intptr_t RoundUp(intptr_t value, intptr_t alignment) {
  return (value + alignment - 1) & ~(alignment - 1);
}

// ========================================================================= //

class MallocBlock;

// A circular buffer to hold freed blocks of memory.  MallocBlock::Deallocate
// (below) pushes blocks into this queue instead of returning them to the
// underlying allocator immediately.  See MallocBlock::Deallocate for more
// information.
//
// We can't use an STL class for this because we need to be careful not to
// perform any heap de-allocations in any of the code in this class, since the
// code in MallocBlock::Deallocate is not re-entrant.
template 
class FreeQueue {
 public:
  FreeQueue() : q_front_(0), q_back_(0) {}

  bool Full() {
    return (q_front_ + 1) % kFreeQueueSize == q_back_;
  }

  void Push(const QueueEntry& block) {
    q_[q_front_] = block;
    q_front_ = (q_front_ + 1) % kFreeQueueSize;
  }

  QueueEntry Pop() {
    RAW_CHECK(q_back_ != q_front_, "Queue is empty");
    const QueueEntry& ret = q_[q_back_];
    q_back_ = (q_back_ + 1) % kFreeQueueSize;
    return ret;
  }

  size_t size() const {
    return (q_front_ - q_back_ + kFreeQueueSize) % kFreeQueueSize;
  }

 private:
  // Maximum number of blocks kept in the free queue before being freed.
  static const int kFreeQueueSize = 1024;

  QueueEntry q_[kFreeQueueSize];
  int q_front_;
  int q_back_;
};

struct MallocBlockQueueEntry {
  MallocBlockQueueEntry() : block(nullptr), size(0),
                            num_deleter_pcs(0) {}
  MallocBlockQueueEntry(MallocBlock* b, size_t s) : block(b), size(s) {
    if (FLAGS_max_free_queue_size != 0 && b != nullptr) {
      num_deleter_pcs = tcmalloc::GrabBacktrace(
        deleter_pcs,
        sizeof(deleter_pcs) / sizeof(deleter_pcs[0]),
        1);
      deleter_threadid = tcmalloc::SelfThreadId();
    } else {
      num_deleter_pcs = 0;
    }
  }

  MallocBlock* block;
  size_t size;

  // When deleted and put in the free queue, we (flag-controlled)
  // record the stack so that if corruption is later found, we can
  // print the deleter's stack.  (These three vars add 144 bytes of
  // overhead under the LP64 data model.)
  void* deleter_pcs[16];
  int num_deleter_pcs;
  uintptr_t deleter_threadid;
};

class MallocBlock {
 public:  // allocation type constants

  // Different allocation types we distinguish.
  // Note: The lower 4 bits are not random: we index kAllocName array
  // by these values masked with kAllocTypeMask;
  // the rest are "random" magic bits to help catch memory corruption.
  static const int kMallocType = 0xEFCDAB90;
  static const int kNewType = 0xFEBADC81;
  static const int kArrayNewType = 0xBCEADF72;

 private:  // constants

  // A mask used on alloc types above to get to 0, 1, 2
  static const int kAllocTypeMask = 0x3;
  // An additional bit to set in AllocType constants
  // to mark now deallocated regions.
  static const int kDeallocatedTypeBit = 0x4;

  // For better memory debugging, we initialize all storage to known
  // values, and overwrite the storage when it's deallocated:
  // Byte that fills uninitialized storage.
  static const int kMagicUninitializedByte = 0xAB;
  // Byte that fills deallocated storage.
  // NOTE: tcmalloc.cc depends on the value of kMagicDeletedByte
  //       to work around a bug in the pthread library.
  static const int kMagicDeletedByte = 0xCD;
  // A size_t (type of alloc_type_ below) in a deallocated storage
  // filled with kMagicDeletedByte.
  static const size_t kMagicDeletedSizeT =
      0xCDCDCDCD | (((size_t)0xCDCDCDCD << 16) << 16);
    // Initializer works for 32 and 64 bit size_ts;
    // "<< 16 << 16" is to fool gcc from issuing a warning
    // when size_ts are 32 bits.

  // NOTE: on Linux, you can enable malloc debugging support in libc by
  // setting the environment variable MALLOC_CHECK_ to 1 before you
  // start the program (see man malloc).

  // We use either do_malloc or mmap to make the actual allocation. In
  // order to remember which one of the two was used for any block, we store an
  // appropriate magic word next to the block.
  static const size_t kMagicMalloc = 0xDEADBEEF;
  static const size_t kMagicMMap = 0xABCDEFAB;

  // This array will be filled with 0xCD, for use with memcmp.
  static unsigned char kMagicDeletedBuffer[1024];
  static tcmalloc::TrivialOnce deleted_buffer_initialized_;

 private:  // data layout

                    // The four fields size1_,offset_,magic1_,alloc_type_
                    // should together occupy a multiple of 16 bytes. (At the
                    // moment, sizeof(size_t) == 4 or 8 depending on piii vs
                    // k8, and 4 of those sum to 16 or 32 bytes).
                    // This, combined with do_malloc's alignment guarantees,
                    // ensures that SSE types can be stored into the returned
                    // block, at &size2_.
  size_t size1_;
  size_t offset_;   // normally 0 unless memaligned memory
                    // see comments in memalign() and FromRawPointer().
  size_t magic1_;
  size_t alloc_type_;
  // here comes the actual data (variable length)
  // ...
  // then come the size2_ and magic2_, or a full page of mprotect-ed memory
  // if the malloc_page_fence feature is enabled.
  size_t size_and_magic2_[2];

 private:  // static data and helpers

  // Allocation map: stores the allocation type for each allocated object,
  // or the type or'ed with kDeallocatedTypeBit
  // for each formerly allocated object.
  typedef AddressMap AllocMap;
  static inline AllocMap* alloc_map_;
  // This protects alloc_map_ and consistent state of metadata
  // for each still-allocated object in it.
  // We use spin locks instead of pthread_mutex_t locks
  // to prevent crashes via calls to pthread_mutex_(un)lock
  // for the (de)allocations coming from pthreads initialization itself.
  static inline SpinLock alloc_map_lock_;

  // A queue of freed blocks.  Instead of releasing blocks to the allocator
  // immediately, we put them in a queue, freeing them only when necessary
  // to keep the total size of all the freed blocks below the limit set by
  // FLAGS_max_free_queue_size.
  static inline FreeQueue* free_queue_;

  static inline size_t free_queue_size_;  // total size of blocks in free_queue_
  // protects free_queue_ and free_queue_size_
  static inline SpinLock free_queue_lock_;

  // Names of allocation types (kMallocType, kNewType, kArrayNewType)
  static const char* const kAllocName[];
  // Names of corresponding deallocation types
  static const char* const kDeallocName[];

  static const char* AllocName(int type) {
    return kAllocName[type & kAllocTypeMask];
  }

  static const char* DeallocName(int type) {
    return kDeallocName[type & kAllocTypeMask];
  }

 private:  // helper accessors

  bool IsMMapped() const { return kMagicMMap == magic1_; }

  bool IsValidMagicValue(size_t value) const {
    return kMagicMMap == value  ||  kMagicMalloc == value;
  }

  static size_t real_malloced_size(size_t size) {
    return size + sizeof(MallocBlock);
  }

  /*
   * Here we assume size of page is kMinAlign aligned,
   * so if size is MALLOC_ALIGNMENT aligned too, then we could
   * guarantee return address is also kMinAlign aligned, because
   * mmap return address at nearby page boundary on Linux.
   */
  static size_t real_mmapped_size(size_t size) {
    size_t tmp = size + MallocBlock::data_offset();
    tmp = RoundUp(tmp, kMinAlign);
    return tmp;
  }

  size_t real_size() {
    return IsMMapped() ? real_mmapped_size(size1_) : real_malloced_size(size1_);
  }

  // NOTE: if the block is mmapped (that is, we're using the
  // malloc_page_fence option) then there's no size2 or magic2
  // (instead, the guard page begins where size2 would be).

  const size_t* size2_addr() const {
    return (const size_t*)((const char*)&size_and_magic2_ + size1_);
  }
  size_t* size2_addr() {
    const auto* cthis = this;
    return const_cast(cthis->size2_addr());
  }

  size_t* magic2_addr() { return (size_t*)(size2_addr() + 1); }
  const size_t* magic2_addr() const { return (const size_t*)(size2_addr() + 1); }

 private:  // other helpers

  void Initialize(size_t size, int type) {
    RAW_CHECK(IsValidMagicValue(magic1_), "");
    // record us as allocated in the map
    alloc_map_lock_.Lock();
    if (!alloc_map_) {
      void* p = do_malloc(sizeof(AllocMap));
      alloc_map_ = new(p) AllocMap(do_malloc, do_free);
    }
    alloc_map_->Insert(data_addr(), type);
    // initialize us
    size1_ = size;
    offset_ = 0;
    alloc_type_ = type;
    if (!IsMMapped()) {
      bit_store(magic2_addr(), &magic1_);
      bit_store(size2_addr(), &size);
    }
    alloc_map_lock_.Unlock();
    memset(data_addr(), kMagicUninitializedByte, size);
    if (!IsMMapped()) {
      RAW_CHECK(memcmp(&size1_, size2_addr(), sizeof(size1_)) == 0, "should hold");
      RAW_CHECK(memcmp(&magic1_, magic2_addr(), sizeof(magic1_)) == 0, "should hold");
    }
  }

  size_t CheckAndClear(int type, size_t given_size) {
    alloc_map_lock_.Lock();
    CheckLocked(type);
    if (!IsMMapped()) {
      RAW_CHECK(memcmp(&size1_, size2_addr(), sizeof(size1_)) == 0, "should hold");
    }
    // record us as deallocated in the map
    alloc_map_->Insert(data_addr(), type | kDeallocatedTypeBit);
    alloc_map_lock_.Unlock();
    // clear us
    const size_t size = real_size();
#if !defined(TCMALLOC_DONT_VERIFY_SIZE)
    RAW_CHECK(!given_size || given_size == size1_,
              "right size must be passed to sized delete");
#endif
    memset(this, kMagicDeletedByte, size);
    return size;
  }

  void CheckLocked(int type) const {
    int map_type = 0;
    const int* found_type =
      alloc_map_ != nullptr ? alloc_map_->Find(data_addr()) : nullptr;
    if (found_type == nullptr) {
      RAW_LOG(FATAL, "memory allocation bug: object at %p "
                     "has never been allocated", data_addr());
    } else {
      map_type = *found_type;
    }
    if ((map_type & kDeallocatedTypeBit) != 0) {
      RAW_LOG(FATAL, "memory allocation bug: object at %p "
                     "has been already deallocated (it was allocated with %s)",
                     data_addr(), AllocName(map_type & ~kDeallocatedTypeBit));
    }
    if (alloc_type_ == kMagicDeletedSizeT) {
      RAW_LOG(FATAL, "memory stomping bug: a word before object at %p "
                     "has been corrupted; or else the object has been already "
                     "deallocated and our memory map has been corrupted",
                     data_addr());
    }
    if (!IsValidMagicValue(magic1_)) {
      RAW_LOG(FATAL, "memory stomping bug: a word before object at %p "
                     "has been corrupted; "
                     "or else our memory map has been corrupted and this is a "
                     "deallocation for not (currently) heap-allocated object",
                     data_addr());
    }
    if (!IsMMapped()) {
      if (memcmp(&size1_, size2_addr(), sizeof(size1_))) {
        RAW_LOG(FATAL, "memory stomping bug: a word after object at %p "
                       "has been corrupted", data_addr());
      }
      size_t addr;
      bit_store(&addr, magic2_addr());
      if (!IsValidMagicValue(addr)) {
        RAW_LOG(FATAL, "memory stomping bug: a word after object at %p "
                "has been corrupted", data_addr());
      }
    }
    if (alloc_type_ != type) {
      if ((alloc_type_ != MallocBlock::kMallocType) &&
          (alloc_type_ != MallocBlock::kNewType)    &&
          (alloc_type_ != MallocBlock::kArrayNewType)) {
        RAW_LOG(FATAL, "memory stomping bug: a word before object at %p "
                       "has been corrupted", data_addr());
      }
      RAW_LOG(FATAL, "memory allocation/deallocation mismatch at %p: "
                     "allocated with %s being deallocated with %s",
                     data_addr(), AllocName(alloc_type_), DeallocName(type));
    }
    if (alloc_type_ != map_type) {
      RAW_LOG(FATAL, "memory stomping bug: our memory map has been corrupted : "
                     "allocation at %p made with %s "
                     "is recorded in the map to be made with %s",
                     data_addr(), AllocName(alloc_type_),  AllocName(map_type));
    }
  }

 public:  // public accessors

  void* data_addr() { return (void*)&size_and_magic2_; }
  const void* data_addr() const { return (const void*)&size_and_magic2_; }

  static size_t data_offset() { return OFFSETOF_MEMBER(MallocBlock, size_and_magic2_); }

  size_t raw_data_size() const { return size1_; }

  // Note, this allocation might actually be from memalign, so raw_ptr
  // might be >= data_addr() (see FromRawPointer and do_debug_memalign
  // for how it works). So in order to get data size we should be
  // careful.
  size_t actual_data_size(const void* raw_ptr) const {
    const char* raw_begin = static_cast(data_addr());
    const char* raw_end = raw_begin + raw_data_size();
    CHECK_CONDITION(raw_begin <= raw_end);
    CHECK_CONDITION(raw_begin <= raw_ptr);
    CHECK_CONDITION(raw_ptr <= raw_end);

    return raw_end - static_cast(raw_ptr);
  }

  void set_offset(int offset) { this->offset_ = offset; }

 public:  // our main interface

  static MallocBlock* Allocate(size_t size, int type) {
    // Prevent an integer overflow / crash with large allocation sizes.
    // TODO - Note that for a e.g. 64-bit size_t, max_size_t may not actually
    // be the maximum value, depending on how the compiler treats ~0. The worst
    // practical effect is that allocations are limited to 4Gb or so, even if
    // the address space could take more.
    static size_t max_size_t = ~0;
    if (size > max_size_t - sizeof(MallocBlock)) {
      RAW_LOG(ERROR, "Massive size passed to malloc: %zu", size);
      return nullptr;
    }
    MallocBlock* b = nullptr;
    const bool use_malloc_page_fence = FLAGS_malloc_page_fence;
    const bool malloc_page_fence_readable = FLAGS_malloc_page_fence_readable;
#ifdef HAVE_MMAP
    if (use_malloc_page_fence) {
      // Put the block towards the end of the page and make the next page
      // inaccessible. This will catch buffer overrun right when it happens.
      size_t sz = real_mmapped_size(size);
      int pagesize = getpagesize();
      int num_pages = (sz + pagesize - 1) / pagesize + 1;
      char* p = (char*) mmap(nullptr, num_pages * pagesize, PROT_READ|PROT_WRITE,
                             MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
      if (p == MAP_FAILED) {
        // If the allocation fails, abort rather than returning nullptr to
        // malloc. This is because in most cases, the program will run out
        // of memory in this mode due to tremendous amount of wastage. There
        // is no point in propagating the error elsewhere.
        RAW_LOG(FATAL, "Out of memory: possibly due to page fence overhead: %s",
                tcmalloc::SafeStrError(errno).c_str());
      }
      // Mark the page after the block inaccessible
      if (mprotect(p + (num_pages - 1) * pagesize, pagesize,
                   PROT_NONE|(malloc_page_fence_readable ? PROT_READ : 0))) {
        RAW_LOG(FATAL, "Guard page setup failed: %s",
                tcmalloc::SafeStrError(errno).c_str());
      }
      b = (MallocBlock*) (p + (num_pages - 1) * pagesize - sz);
    } else {
      b = (MallocBlock*) do_malloc(real_malloced_size(size));
    }
#else
    b = (MallocBlock*) do_malloc(real_malloced_size(size));
#endif

    // It would be nice to output a diagnostic on allocation failure
    // here, but logging (other than FATAL) requires allocating
    // memory, which could trigger a nasty recursion. Instead, preserve
    // malloc semantics and return nullptr on failure.
    if (b != nullptr) {
      b->magic1_ = use_malloc_page_fence ? kMagicMMap : kMagicMalloc;
      b->Initialize(size, type);
    }
    return b;
  }

  void Deallocate(int type, size_t given_size) {
    if (IsMMapped()) {  // have to do this before CheckAndClear
#ifdef HAVE_MMAP
      int size = CheckAndClear(type, given_size);
      int pagesize = getpagesize();
      int num_pages = (size + pagesize - 1) / pagesize + 1;
      char* p = (char*) this;
      if (FLAGS_malloc_page_fence_never_reclaim  ||
          !FLAGS_malloc_reclaim_memory) {
        mprotect(p - (num_pages - 1) * pagesize + size,
                 num_pages * pagesize, PROT_NONE);
      } else {
        munmap(p - (num_pages - 1) * pagesize + size, num_pages * pagesize);
      }
#endif
    } else {
      const size_t size = CheckAndClear(type, given_size);
      if (FLAGS_malloc_reclaim_memory) {
        // Instead of freeing the block immediately, push it onto a queue of
        // recently freed blocks.  Free only enough blocks to keep from
        // exceeding the capacity of the queue or causing the total amount of
        // un-released memory in the queue from exceeding
        // FLAGS_max_free_queue_size.
        ProcessFreeQueue(this, size, FLAGS_max_free_queue_size);
      }
    }
  }

  static size_t FreeQueueSize() {
    SpinLockHolder l(&free_queue_lock_);
    return free_queue_size_;
  }

  static void ProcessFreeQueue(MallocBlock* b, size_t size,
                               int max_free_queue_size) {
    // MallocBlockQueueEntry are about 144 in size, so we can only
    // use a small array of them on the stack.
    MallocBlockQueueEntry entries[4];
    int num_entries = 0;
    MallocBlockQueueEntry new_entry(b, size);
    free_queue_lock_.Lock();
    if (free_queue_ == nullptr)
      free_queue_ = new FreeQueue;
    RAW_CHECK(!free_queue_->Full(), "Free queue mustn't be full!");

    if (b != nullptr) {
      free_queue_size_ += size + sizeof(MallocBlockQueueEntry);
      free_queue_->Push(new_entry);
    }

    // Free blocks until the total size of unfreed blocks no longer exceeds
    // max_free_queue_size, and the free queue has at least one free
    // space in it.
    while (free_queue_size_ > max_free_queue_size || free_queue_->Full()) {
      RAW_CHECK(num_entries < arraysize(entries), "entries array overflow");
      entries[num_entries] = free_queue_->Pop();
      free_queue_size_ -=
          entries[num_entries].size + sizeof(MallocBlockQueueEntry);
      num_entries++;
      if (num_entries == arraysize(entries)) {
        // The queue will not be full at this point, so it is ok to
        // release the lock.  The queue may still contain more than
        // max_free_queue_size, but this is not a strict invariant.
        free_queue_lock_.Unlock();
        for (int i = 0; i < num_entries; i++) {
          CheckForDanglingWrites(entries[i]);
          do_free(entries[i].block);
        }
        num_entries = 0;
        free_queue_lock_.Lock();
      }
    }
    free_queue_lock_.Unlock();
    for (int i = 0; i < num_entries; i++) {
      CheckForDanglingWrites(entries[i]);
      do_free(entries[i].block);
    }
  }

  static void InitDeletedBuffer() {
    memset(kMagicDeletedBuffer, kMagicDeletedByte, sizeof(kMagicDeletedBuffer));
  }

  static void CheckForDanglingWrites(const MallocBlockQueueEntry& queue_entry) {
    // Initialize the buffer if necessary.
    deleted_buffer_initialized_.RunOnce(&InitDeletedBuffer);

    const unsigned char* p =
        reinterpret_cast(queue_entry.block);

    static const size_t size_of_buffer = sizeof(kMagicDeletedBuffer);
    const size_t size = queue_entry.size;
    const size_t buffers = size / size_of_buffer;
    const size_t remainder = size % size_of_buffer;
    size_t buffer_idx;
    for (buffer_idx = 0; buffer_idx < buffers; ++buffer_idx) {
      CheckForCorruptedBuffer(queue_entry, buffer_idx, p, size_of_buffer);
      p += size_of_buffer;
    }
    CheckForCorruptedBuffer(queue_entry, buffer_idx, p, remainder);
  }

  static void CheckForCorruptedBuffer(const MallocBlockQueueEntry& queue_entry,
                                      size_t buffer_idx,
                                      const unsigned char* buffer,
                                      size_t size_of_buffer) {
    if (memcmp(buffer, kMagicDeletedBuffer, size_of_buffer) == 0) {
      return;
    }

    RAW_LOG(ERROR,
            "Found a corrupted memory buffer in MallocBlock (may be offset "
            "from user ptr): buffer index: %zd, buffer ptr: %p, size of "
            "buffer: %zd", buffer_idx, buffer, size_of_buffer);

    // The magic deleted buffer should only be 1024 bytes, but in case
    // this changes, let's put an upper limit on the number of debug
    // lines we'll output:
    if (size_of_buffer <= 1024) {
      for (int i = 0; i < size_of_buffer; ++i) {
        if (buffer[i] != kMagicDeletedByte) {
          RAW_LOG(ERROR, "Buffer byte %d is 0x%02x (should be 0x%02x).",
                  i, buffer[i], kMagicDeletedByte);
        }
      }
    } else {
      RAW_LOG(ERROR, "Buffer too large to print corruption.");
    }

    const MallocBlock* b = queue_entry.block;
    const size_t size = queue_entry.size;
    if (queue_entry.num_deleter_pcs > 0) {
      TracePrintf(STDERR_FILENO, "Deleted by thread %zx\n",
                  queue_entry.deleter_threadid);

      ThreadCachePtr::WithStacktraceScope([&] (bool stacktrace_allowed) {
        tcmalloc::DumpStackTraceToStderr(queue_entry.deleter_pcs, queue_entry.num_deleter_pcs,
                                         FLAGS_symbolize_stacktrace,
                                         "    @ ");
      });
    } else {
      RAW_LOG(ERROR,
              "Skipping the printing of the deleter's stack!  Its stack was "
              "not found; either the corruption occurred too early in "
              "execution to obtain a stack trace or --max_free_queue_size was "
              "set to 0.");
    }

    RAW_LOG(FATAL,
            "Memory was written to after being freed.  MallocBlock: %p, user "
            "ptr: %p, size: %zd.  If you can't find the source of the error, "
            "try using ASan (https://github.com/google/sanitizers), "
            "Valgrind, or Purify, or study the "
            "output of the deleter's stack printed above.",
            b, b->data_addr(), size);
  }

  static MallocBlock* FromRawPointer(void* p) {
    const size_t data_offset = MallocBlock::data_offset();
    // Find the header just before client's memory.
    MallocBlock *mb = reinterpret_cast(
                reinterpret_cast(p) - data_offset);
    // If mb->alloc_type_ is kMagicDeletedSizeT, we're not an ok pointer.
    if (mb->alloc_type_ == kMagicDeletedSizeT) {
      RAW_LOG(FATAL, "memory allocation bug: object at %p has been already"
                     " deallocated; or else a word before the object has been"
                     " corrupted (memory stomping bug)", p);
    }
    // If mb->offset_ is zero (common case), mb is the real header.
    // If mb->offset_ is non-zero, this block was allocated by debug
    // memallign implementation, and mb->offset_ is the distance
    // backwards to the real header from mb, which is a fake header.
    if (mb->offset_ == 0) {
      return mb;
    }

    MallocBlock *main_block = reinterpret_cast(
      reinterpret_cast(mb) - mb->offset_);

    if (main_block->offset_ != 0) {
      RAW_LOG(FATAL, "memory corruption bug: offset_ field is corrupted."
              " Need 0 but got %x",
              (unsigned)(main_block->offset_));
    }
    if (main_block >= p) {
      RAW_LOG(FATAL, "memory corruption bug: offset_ field is corrupted."
              " Detected main_block address overflow: %x",
              (unsigned)(mb->offset_));
    }
    if (main_block->size2_addr() < p) {
      RAW_LOG(FATAL, "memory corruption bug: offset_ field is corrupted."
              " It points below it's own main_block: %x",
              (unsigned)(mb->offset_));
    }

    return main_block;
  }

  static const MallocBlock* FromRawPointer(const void* p) {
    // const-safe version: we just cast about
    return FromRawPointer(const_cast(p));
  }

  void Check(int type) const {
    alloc_map_lock_.Lock();
    CheckLocked(type);
    alloc_map_lock_.Unlock();
  }

  static bool CheckEverything() {
    alloc_map_lock_.Lock();
    if (alloc_map_) {
      alloc_map_->Iterate([] (const void* ptr, int* type) {
        if ((*type & kDeallocatedTypeBit) == 0) {
          FromRawPointer(ptr)->CheckLocked(*type);
        }
      });
    }
    alloc_map_lock_.Unlock();
    return true;  // if we get here, we're okay
  }

  static bool MemoryStats(int* blocks, size_t* total,
                          int histogram[kMallocHistogramSize]) {
    memset(histogram, 0, kMallocHistogramSize * sizeof(int));
    alloc_map_lock_.Lock();
    stats_blocks_ = 0;
    stats_total_ = 0;
    stats_histogram_ = histogram;

    if (alloc_map_) {
      alloc_map_->Iterate([] (const void* ptr, int* type) {
        if ((*type & kDeallocatedTypeBit) == 0) {
          const MallocBlock* b = FromRawPointer(ptr);
          b->CheckLocked(*type);
          ++stats_blocks_;
          size_t mysize = b->size1_;
          int entry = 0;
          stats_total_ += mysize;
          while (mysize) {
            ++entry;
            mysize >>= 1;
          }
          RAW_CHECK(entry < kMallocHistogramSize,
                    "kMallocHistogramSize should be at least as large as log2 "
                    "of the maximum process memory size");
          stats_histogram_[entry] += 1;
        }
      });
    }

    *blocks = stats_blocks_;
    *total = stats_total_;
    alloc_map_lock_.Unlock();
    return true;
  }

 private:  // helpers for CheckEverything and MemoryStats

  // Accumulation variables for StatsCallback protected by alloc_map_lock_
  static int stats_blocks_;
  static size_t stats_total_;
  static int* stats_histogram_;
};

void DanglingWriteChecker() {
  // Clear out the remaining free queue to check for dangling writes.
  MallocBlock::ProcessFreeQueue(nullptr, 0, 0);
}

// ========================================================================= //

const size_t MallocBlock::kMagicMalloc;
const size_t MallocBlock::kMagicMMap;

unsigned char MallocBlock::kMagicDeletedBuffer[1024];
tcmalloc::TrivialOnce MallocBlock::deleted_buffer_initialized_;

const char* const MallocBlock::kAllocName[] = {
  "malloc",
  "new",
  "new []",
  nullptr,
};

const char* const MallocBlock::kDeallocName[] = {
  "free",
  "delete",
  "delete []",
  nullptr,
};

int MallocBlock::stats_blocks_;
size_t MallocBlock::stats_total_;
int* MallocBlock::stats_histogram_;

// ========================================================================= //

// The following cut-down version of printf() avoids
// using stdio or ostreams.
// This is to guarantee no recursive calls into
// the allocator and to bound the stack space consumed.  (The pthread
// manager thread in linuxthreads has a very small stack,
// so fprintf can't be called.)
static void TracePrintf(int fd, const char *fmt, ...) {
  char buf[64];
  int i = 0;
  va_list ap;
  va_start(ap, fmt);
  const char *p = fmt;
  char numbuf[25];
  if (fd < 0) {
    va_end(ap);
    return;
  }
  numbuf[sizeof(numbuf)-1] = 0;
  while (*p != '\0') {              // until end of format string
    char *s = &numbuf[sizeof(numbuf)-1];
    if (p[0] == '%' && p[1] != 0) {  // handle % formats
      int64_t l = 0;
      unsigned long base = 0;
      if (*++p == 's') {                            // %s
        s = va_arg(ap, char *);
      } else if (*p == 'l' && p[1] == 'd') {        // %ld
        l = va_arg(ap, long);
        base = 10;
        p++;
      } else if (*p == 'l' && p[1] == 'u') {        // %lu
        l = va_arg(ap, unsigned long);
        base = 10;
        p++;
      } else if (*p == 'z' && p[1] == 'u') {        // %zu
        l = va_arg(ap, size_t);
        base = 10;
        p++;
      } else if (*p == 'z' && p[1] == 'x') {        // %zx
        l = va_arg(ap, size_t);
        base = 16;
        p++;
      } else if (*p == 'u') {                       // %u
        l = va_arg(ap, unsigned int);
        base = 10;
      } else if (*p == 'd') {                       // %d
        l = va_arg(ap, int);
        base = 10;
      } else if (*p == 'p') {                       // %p
        l = va_arg(ap, intptr_t);
        base = 16;
      } else {
        WRITE_TO_STDERR("Unimplemented TracePrintf format\n", 33);
        WRITE_TO_STDERR(p, 2);
        WRITE_TO_STDERR("\n", 1);
        abort();
      }
      p++;
      if (base != 0) {
        bool minus = (l < 0 && base == 10);
        uint64_t ul = minus? -l : l;
        do {
          *--s = "0123456789abcdef"[ul % base];
          ul /= base;
        } while (ul != 0);
        if (base == 16) {
          *--s = 'x';
          *--s = '0';
        } else if (minus) {
          *--s = '-';
        }
      }
    } else {                        // handle normal characters
      *--s = *p++;
    }
    while (*s != 0) {
      if (i == sizeof(buf)) {
        auto unused = write(fd, buf, i);
        (void)unused;
        i = 0;
      }
      buf[i++] = *s++;
    }
  }
  if (i != 0) {
    auto unused = write(fd, buf, i);
    (void)unused;
  }
  va_end(ap);
}

// Return the file descriptor we're writing a log to
static int TraceFd() {
  static int trace_fd = -1;
  if (trace_fd == -1) {            // Open the trace file on the first call
    const char *val = getenv("TCMALLOC_TRACE_FILE");
    bool fallback_to_stderr = false;
    if (!val) {
      val = "/tmp/google.alloc";
      fallback_to_stderr = true;
    }
    trace_fd = open(val, O_CREAT|O_TRUNC|O_WRONLY, 0666);
    if (trace_fd == -1) {
      if (fallback_to_stderr) {
        trace_fd = 2;
        TracePrintf(trace_fd, "Can't open %s.  Logging to stderr.\n", val);
      } else {
        TracePrintf(2, "Can't open %s.  Logging disabled.\n", val);
      }
    }
    // Add a header to the log.
    TracePrintf(trace_fd, "Trace started: %lu\n",
                static_cast(time(nullptr)));
    TracePrintf(trace_fd,
                "func\tsize\tptr\tthread_id\tstack pcs for tools/symbolize\n");
  }
  return trace_fd;
}

// Print the hex stack dump on a single line.   PCs are separated by tabs.
static void TraceStack(void) {
  void *pcs[16];
  int n = tcmalloc::GrabBacktrace(pcs, sizeof(pcs)/sizeof(pcs[0]), 0);
  for (int i = 0; i != n; i++) {
    TracePrintf(TraceFd(), "\t%p", pcs[i]);
  }
}

// This protects MALLOC_TRACE, to make sure its info is atomically written.
static SpinLock malloc_trace_lock;

#define MALLOC_TRACE(name, size, addr)                                               \
  do {                                                                               \
    if (FLAGS_malloctrace) {                                                         \
      SpinLockHolder l(&malloc_trace_lock);                                          \
      TracePrintf(TraceFd(), "%s\t%zu\t%p\t%zu",                                     \
                  name, size, addr, tcmalloc::SelfThreadId());                       \
      TraceStack();                                                                  \
      TracePrintf(TraceFd(), "\n");                                                  \
    }                                                                                \
  } while (0)

// ========================================================================= //

// Write the characters buf[0, ..., size-1] to
// the malloc trace buffer.
// This function is intended for debugging,
// and is not declared in any header file.
// You must insert a declaration of it by hand when you need
// to use it.
void __malloctrace_write(const char *buf, size_t size) {
  if (FLAGS_malloctrace) {
    auto unused = write(TraceFd(), buf, size);
    (void)unused;
  }
}

// ========================================================================= //

// General debug allocation/deallocation

static inline void* DebugAllocate(size_t size, int type) {
  if (PREDICT_FALSE(tcmalloc::ThreadCachePtr::Grab().IsEmergencyMallocEnabled())) {
    return tcmalloc::EmergencyMalloc(size);
  }

#if defined(__APPLE__)
  // OSX malloc zones integration has some odd behavior. When
  // GetAllocatedSize returns 0 it appears to assume something wrong
  // about the pointer. And since in debug allocator we can return 0
  // if original size was also 0, lets avoid this case. But only on
  // OSX. It weakens debug checks a bit, but it unbreaks some tests
  // (around realloc/free of 0-sized chunks).
  if (size == 0) size = 1;
#endif
  MallocBlock* ptr = MallocBlock::Allocate(size, type);
  if (ptr == nullptr)  return nullptr;
  MALLOC_TRACE("malloc", size, ptr->data_addr());
  return ptr->data_addr();
}

static inline void DebugDeallocate(void* ptr, int type, size_t given_size) {
  if (PREDICT_FALSE(tcmalloc::IsEmergencyPtr(ptr))) {
    return tcmalloc::EmergencyFree(ptr);
  }

  MALLOC_TRACE("free",
               (ptr != 0 ? MallocBlock::FromRawPointer(ptr)->actual_data_size(ptr) : 0),
               ptr);
  if (ptr)  MallocBlock::FromRawPointer(ptr)->Deallocate(type, given_size);
}

class ATTRIBUTE_VISIBILITY_HIDDEN DebugTestingPortal : public TestingPortalImpl {
public:
  ~DebugTestingPortal() override = default;
  bool IsDebuggingMalloc() override { return true; }
  int32_t& GetMaxFreeQueueSize() override { return FLAGS_max_free_queue_size; }
  uint32_t GetSizeClass(void*) override { return 0; }
  void* RunReallocWithCallback(
    void* old_ptr, size_t new_size,
    void (*invalid_free_fn)(void*),
    size_t (*invalid_get_size_fn)(const void*)) override {
    RAW_LOG(FATAL, "RunReallocWithCallback is not implemented for debugallocation");
    return nullptr;
  }
};

// ========================================================================= //

// The following functions may be called via MallocExtension::instance()
// for memory verification and statistics.
class DebugMallocImplementation : public TCMallocImplementation {
 public:
  virtual bool GetNumericProperty(const char* name, size_t* value) {
    if (TestingPortal** portal = TestingPortal::CheckGetPortal(name, value); portal) {
      static DebugTestingPortal* ptr = ([] () {
        static tcmalloc::StaticStorage storage;
        return storage.Construct();
      })();
      *portal = ptr;
      *value = 1;
      return true;
    }

    bool result = TCMallocImplementation::GetNumericProperty(name, value);
    if (result && (strcmp(name, "generic.current_allocated_bytes") == 0)) {
      // Subtract bytes kept in the free queue
      size_t qsize = MallocBlock::FreeQueueSize();
      if (*value >= qsize) {
        *value -= qsize;
      }
    }
    return result;
  }

  virtual bool VerifyNewMemory(const void* p) {
    if (p)  MallocBlock::FromRawPointer(p)->Check(MallocBlock::kNewType);
    return true;
  }

  virtual bool VerifyArrayNewMemory(const void* p) {
    if (p)  MallocBlock::FromRawPointer(p)->Check(MallocBlock::kArrayNewType);
    return true;
  }

  virtual bool VerifyMallocMemory(const void* p) {
    if (p)  MallocBlock::FromRawPointer(p)->Check(MallocBlock::kMallocType);
    return true;
  }

  virtual bool VerifyAllMemory() {
    return MallocBlock::CheckEverything();
  }

  virtual bool MallocMemoryStats(int* blocks, size_t* total,
                                 int histogram[kMallocHistogramSize]) {
    return MallocBlock::MemoryStats(blocks, total, histogram);
  }

  virtual size_t GetEstimatedAllocatedSize(size_t size) {
    return size;
  }

  virtual size_t GetAllocatedSize(const void* p) {
    if (p) {
      RAW_CHECK(GetOwnership(p) != MallocExtension::kNotOwned,
                "ptr not allocated by tcmalloc");
      if (tcmalloc::IsEmergencyPtr(p)) {
        return tcmalloc::EmergencyAllocatedSize(p);
      }
      return MallocBlock::FromRawPointer(p)->actual_data_size(p);
    }
    return 0;
  }

  virtual MallocExtension::Ownership GetOwnership(const void* p) {
    if (!p) {
      // nobody owns nullptr
      return MallocExtension::kNotOwned;
    }

    // FIXME: note that correct GetOwnership should not touch memory
    // that is not owned by tcmalloc. Main implementation is using
    // pagemap to discover if page in question is owned by us or
    // not. But pagemap only has marks for first and last page of
    // spans.  Note that if p was returned out of our memalign with
    // big alignment, then it will point outside of marked pages. Also
    // note that FromRawPointer call below requires touching memory
    // before pointer in order to handle memalign-ed chunks
    // (offset_). This leaves us with two options:
    //
    // * do FromRawPointer first and have possibility of crashing if
    //   we're given not owned pointer
    //
    // * return incorrect ownership for those large memalign chunks
    //
    // I've decided to choose later, which appears to happen rarer and
    // therefore is arguably a lesser evil

    MallocExtension::Ownership rv = TCMallocImplementation::GetOwnership(p);
    if (rv != MallocExtension::kOwned) {
      return rv;
    }

    if (tcmalloc::IsEmergencyPtr(p)) {
      return kOwned;
    }

    const MallocBlock* mb = MallocBlock::FromRawPointer(p);
    return TCMallocImplementation::GetOwnership(mb);
  }

  virtual void GetFreeListSizes(std::vector* v) {
    static const char* kDebugFreeQueue = "debug.free_queue";

    TCMallocImplementation::GetFreeListSizes(v);

    MallocExtension::FreeListInfo i;
    i.type = kDebugFreeQueue;
    i.min_object_size = 0;
    i.max_object_size = std::numeric_limits::max();
    i.total_bytes_free = MallocBlock::FreeQueueSize();
    v->push_back(i);
  }

};

static tcmalloc::StaticStorage debug_malloc_impl_storage;

void SetupMallocExtension() {
  MallocExtension::Register(debug_malloc_impl_storage.Construct());
}

REGISTER_MODULE_DESTRUCTOR(debugallocation, {
  if (!RunningOnValgrind()) {
    // When the program exits, check all blocks still in the free
    // queue for corruption.
    DanglingWriteChecker();
  }
});

// ========================================================================= //

struct debug_alloc_retry_data {
  size_t size;
  int new_type;
};

static void *retry_debug_allocate(void *arg) {
  debug_alloc_retry_data *data = static_cast(arg);
  return DebugAllocate(data->size, data->new_type);
}

// This is mostly the same a cpp_alloc in tcmalloc.cc.
// TODO(csilvers): change Allocate() above to call cpp_alloc, so we
// don't have to reproduce the logic here.  To make tc_new_mode work
// properly, I think we'll need to separate out the logic of throwing
// from the logic of calling the new-handler.
inline void* debug_cpp_alloc(size_t size, int new_type, bool nothrow) {
  void* p = DebugAllocate(size, new_type);
  if (p != nullptr) {
    return p;
  }
  struct debug_alloc_retry_data data;
  data.size = size;
  data.new_type = new_type;
  return handle_oom(retry_debug_allocate, &data,
                    true, nothrow);
}

inline void* do_debug_malloc_or_debug_cpp_alloc(size_t size) {
  void* p = DebugAllocate(size, MallocBlock::kMallocType);
  if (p != nullptr) {
    return p;
  }
  struct debug_alloc_retry_data data;
  data.size = size;
  data.new_type = MallocBlock::kMallocType;
  return handle_oom(retry_debug_allocate, &data,
                    false, true);
}

// Exported routines

// frame forcer and force_frame exist only to prevent tail calls to
// DebugDeallocate to be actually implemented as tail calls. This is
// important because stack trace capturing in MallocBlockQueueEntry
// relies on google_malloc section being on stack and tc_XXX functions
// are in that section. So they must not jump to DebugDeallocate but
// have to do call. frame_forcer call at the end of such functions
// prevents tail calls to DebugDeallocate.
static int frame_forcer;
static void force_frame() {
  int dummy = *(int volatile *)&frame_forcer;
  (void)dummy;
}

extern "C" PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) PERFTOOLS_NOTHROW {
  void* ptr = do_debug_malloc_or_debug_cpp_alloc(size);
  tcmalloc::InvokeNewHook(ptr, size);
  return ptr;
}

extern "C" PERFTOOLS_DLL_DECL void tc_free(void* ptr) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(ptr);
  DebugDeallocate(ptr, MallocBlock::kMallocType, 0);
  force_frame();
}

extern "C" PERFTOOLS_DLL_DECL void tc_free_sized(void *ptr, size_t size) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(ptr);
  DebugDeallocate(ptr, MallocBlock::kMallocType, size);
  force_frame();
}

extern "C" PERFTOOLS_DLL_DECL void tc_free_aligned_sized(void* ptr, size_t align, size_t size) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(ptr);
  DebugDeallocate(ptr, MallocBlock::kMallocType, 0);
  force_frame();
}

extern "C" PERFTOOLS_DLL_DECL void* tc_calloc(size_t count, size_t size) PERFTOOLS_NOTHROW {
  // Overflow check
  const size_t total_size = count * size;
  if (size != 0 && total_size / size != count) return nullptr;

  void* block = do_debug_malloc_or_debug_cpp_alloc(total_size);
  if (block)  memset(block, 0, total_size);
  tcmalloc::InvokeNewHook(block, total_size);
  return block;
}

extern "C" PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(ptr);
  DebugDeallocate(ptr, MallocBlock::kMallocType, 0);
  force_frame();
}

extern "C" PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) PERFTOOLS_NOTHROW {
  if (ptr == nullptr) {
    ptr = do_debug_malloc_or_debug_cpp_alloc(size);
    tcmalloc::InvokeNewHook(ptr, size);
    return ptr;
  }
  if (size == 0) {
    tcmalloc::InvokeDeleteHook(ptr);
    DebugDeallocate(ptr, MallocBlock::kMallocType, 0);
    return nullptr;
  }

  if (PREDICT_FALSE(tcmalloc::IsEmergencyPtr(ptr))) {
    return tcmalloc::EmergencyRealloc(ptr, size);
  }

  MallocBlock* old = MallocBlock::FromRawPointer(ptr);
  old->Check(MallocBlock::kMallocType);
  MallocBlock* p = MallocBlock::Allocate(size, MallocBlock::kMallocType);

  // If realloc fails we are to leave the old block untouched and
  // return null
  if (p == nullptr)  return nullptr;

  size_t old_size = old->actual_data_size(ptr);

  memcpy(p->data_addr(), ptr, (old_size < size) ? old_size : size);
  tcmalloc::InvokeDeleteHook(ptr);
  tcmalloc::InvokeNewHook(p->data_addr(), size);
  DebugDeallocate(ptr, MallocBlock::kMallocType, 0);
  MALLOC_TRACE("realloc", p->actual_data_size(p->data_addr()), p->data_addr());
  return p->data_addr();
}

extern "C" PERFTOOLS_DLL_DECL void* tc_new(size_t size) {
  void* ptr = debug_cpp_alloc(size, MallocBlock::kNewType, false);
  tcmalloc::InvokeNewHook(ptr, size);
  if (ptr == nullptr) {
    RAW_LOG(FATAL, "Unable to allocate %zu bytes: new failed.", size);
  }
  return ptr;
}

extern "C" PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, const std::nothrow_t&) PERFTOOLS_NOTHROW {
  void* ptr = debug_cpp_alloc(size, MallocBlock::kNewType, true);
  tcmalloc::InvokeNewHook(ptr, size);
  return ptr;
}

extern "C" PERFTOOLS_DLL_DECL void tc_delete(void* p) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(p);
  DebugDeallocate(p, MallocBlock::kNewType, 0);
  force_frame();
}

extern "C" PERFTOOLS_DLL_DECL void tc_delete_sized(void* p, size_t size) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(p);
  DebugDeallocate(p, MallocBlock::kNewType, size);
  force_frame();
}

// Some STL implementations explicitly invoke this.
// It is completely equivalent to a normal delete (delete never throws).
extern "C" PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(p);
  DebugDeallocate(p, MallocBlock::kNewType, 0);
  force_frame();
}

extern "C" PERFTOOLS_DLL_DECL void* tc_newarray(size_t size) {
  void* ptr = debug_cpp_alloc(size, MallocBlock::kArrayNewType, false);
  tcmalloc::InvokeNewHook(ptr, size);
  if (ptr == nullptr) {
    RAW_LOG(FATAL, "Unable to allocate %zu bytes: new[] failed.", size);
  }
  return ptr;
}

extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&)
    PERFTOOLS_NOTHROW {
  void* ptr = debug_cpp_alloc(size, MallocBlock::kArrayNewType, true);
  tcmalloc::InvokeNewHook(ptr, size);
  return ptr;
}

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray(void* p) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(p);
  DebugDeallocate(p, MallocBlock::kArrayNewType, 0);
  force_frame();
}

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_sized(void* p, size_t size) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(p);
  DebugDeallocate(p, MallocBlock::kArrayNewType, size);
  force_frame();
}

// Some STL implementations explicitly invoke this.
// It is completely equivalent to a normal delete (delete never throws).
extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) PERFTOOLS_NOTHROW {
  tcmalloc::InvokeDeleteHook(p);
  DebugDeallocate(p, MallocBlock::kArrayNewType, 0);
  force_frame();
}

// This is mostly the same as do_memalign in tcmalloc.cc.
static void *do_debug_memalign(size_t alignment, size_t size, int type) {
  // Allocate >= size bytes aligned on "alignment" boundary
  // "alignment" is a power of two.
  void *p = 0;
  RAW_CHECK((alignment & (alignment-1)) == 0, "must be power of two");
  const size_t data_offset = MallocBlock::data_offset();
  // Allocate "alignment-1" extra bytes to ensure alignment is possible, and
  // a further data_offset bytes for an additional fake header.
  size_t extra_bytes = data_offset + alignment - 1;
  if (size + extra_bytes < size) return nullptr;         // Overflow
  p = DebugAllocate(size + extra_bytes, type);
  if (p != 0) {
    intptr_t orig_p = reinterpret_cast(p);
    // Leave data_offset bytes for fake header, and round up to meet
    // alignment.
    p = reinterpret_cast(RoundUp(orig_p + data_offset, alignment));
    // Create a fake header block with an offset_ that points back to the
    // real header.  FromRawPointer uses this value.
    MallocBlock *fake_hdr = reinterpret_cast(
                reinterpret_cast(p) - data_offset);
    // offset_ is distance between real and fake headers.
    // p is now end of fake header (beginning of client area),
    // and orig_p is the end of the real header, so offset_
    // is their difference.
    //
    // Note that other fields of fake_hdr are initialized with
    // kMagicUninitializedByte
    fake_hdr->set_offset(reinterpret_cast(p) - orig_p);
  }
  return p;
}

struct memalign_retry_data {
  size_t align;
  size_t size;
  int type;
};

static void *retry_debug_memalign(void *arg) {
  memalign_retry_data *data = static_cast(arg);
  return do_debug_memalign(data->align, data->size, data->type);
}

ALWAYS_INLINE
void* do_debug_memalign_or_debug_cpp_memalign(size_t align,
                                                     size_t size,
                                                     int type,
                                                     bool from_operator,
                                                     bool nothrow) {
  void* p = do_debug_memalign(align, size, type);
  if (p != nullptr) {
    return p;
  }

  struct memalign_retry_data data;
  data.align = align;
  data.size = size;
  data.type = type;
  return handle_oom(retry_debug_memalign, &data,
                    from_operator, nothrow);
}

extern "C" PERFTOOLS_DLL_DECL void* tc_memalign(size_t align, size_t size) PERFTOOLS_NOTHROW {
  void *p = do_debug_memalign_or_debug_cpp_memalign(align, size, MallocBlock::kMallocType, false, true);
  tcmalloc::InvokeNewHook(p, size);
  return p;
}

// Implementation taken from tcmalloc/tcmalloc.cc
extern "C" PERFTOOLS_DLL_DECL int tc_posix_memalign(void** result_ptr, size_t align, size_t size)
    PERFTOOLS_NOTHROW {
  if (((align % sizeof(void*)) != 0) ||
      ((align & (align - 1)) != 0) ||
      (align == 0)) {
    return EINVAL;
  }

  void* result = do_debug_memalign_or_debug_cpp_memalign(align, size, MallocBlock::kMallocType, false, true);
  tcmalloc::InvokeNewHook(result, size);
  if (result == nullptr) {
    return ENOMEM;
  } else {
    *result_ptr = result;
    return 0;
  }
}

extern "C" PERFTOOLS_DLL_DECL void* tc_valloc(size_t size) PERFTOOLS_NOTHROW {
  // Allocate >= size bytes starting on a page boundary
  void *p = do_debug_memalign_or_debug_cpp_memalign(getpagesize(), size, MallocBlock::kMallocType, false, true);
  tcmalloc::InvokeNewHook(p, size);
  return p;
}

extern "C" PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t size) PERFTOOLS_NOTHROW {
  // Round size up to a multiple of pages
  // then allocate memory on a page boundary
  int pagesize = getpagesize();
  size = RoundUp(size, pagesize);
  if (size == 0) {     // pvalloc(0) should allocate one page, according to
    size = pagesize;   // http://man.free4web.biz/man3/libmpatrol.3.html
  }
  void *p = do_debug_memalign_or_debug_cpp_memalign(pagesize, size, MallocBlock::kMallocType, false, true);
  tcmalloc::InvokeNewHook(p, size);
  return p;
}

extern "C" PERFTOOLS_DLL_DECL void* tc_new_aligned(size_t size, std::align_val_t align) {
  void* result = do_debug_memalign_or_debug_cpp_memalign(static_cast(align), size, MallocBlock::kNewType, true, false);
  tcmalloc::InvokeNewHook(result, size);
  return result;
}

extern "C" PERFTOOLS_DLL_DECL void* tc_new_aligned_nothrow(size_t size, std::align_val_t align, const std::nothrow_t&) PERFTOOLS_NOTHROW {
  void* result = do_debug_memalign_or_debug_cpp_memalign(static_cast(align), size, MallocBlock::kNewType, true, true);
  tcmalloc::InvokeNewHook(result, size);
  return result;
}

extern "C" PERFTOOLS_DLL_DECL void tc_delete_aligned(void* p, std::align_val_t) PERFTOOLS_NOTHROW {
  tc_delete(p);
}

extern "C" PERFTOOLS_DLL_DECL void tc_delete_sized_aligned(void* p, size_t size, std::align_val_t align) PERFTOOLS_NOTHROW {
  // Reproduce actual size calculation done by do_debug_memalign
  const size_t alignment = static_cast(align);
  const size_t data_offset = MallocBlock::data_offset();
  const size_t extra_bytes = data_offset + alignment - 1;

  tc_delete_sized(p, size + extra_bytes);
}

extern "C" PERFTOOLS_DLL_DECL void tc_delete_aligned_nothrow(void* p, std::align_val_t, const std::nothrow_t&) PERFTOOLS_NOTHROW {
  tc_delete(p);
}

extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_aligned(size_t size, std::align_val_t align) {
  void* result = do_debug_memalign_or_debug_cpp_memalign(static_cast(align), size, MallocBlock::kArrayNewType, true, false);
  tcmalloc::InvokeNewHook(result, size);
  return result;
}

extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_aligned_nothrow(size_t size, std::align_val_t align, const std::nothrow_t& nt) PERFTOOLS_NOTHROW {
  void* result = do_debug_memalign_or_debug_cpp_memalign(static_cast(align), size, MallocBlock::kArrayNewType, true, true);
  tcmalloc::InvokeNewHook(result, size);
  return result;
}

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_aligned(void* p, std::align_val_t) PERFTOOLS_NOTHROW {
  tc_deletearray(p);
}

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_sized_aligned(void* p, size_t size, std::align_val_t align) PERFTOOLS_NOTHROW {
  // Reproduce actual size calculation done by do_debug_memalign
  const size_t alignment = static_cast(align);
  const size_t data_offset = MallocBlock::data_offset();
  const size_t extra_bytes = data_offset + alignment - 1;

  tc_deletearray_sized(p, size + extra_bytes);
}

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_aligned_nothrow(void* p, std::align_val_t, const std::nothrow_t&) PERFTOOLS_NOTHROW {
  tc_deletearray(p);
}

// malloc_stats just falls through to the base implementation.
extern "C" PERFTOOLS_DLL_DECL void tc_malloc_stats(void) PERFTOOLS_NOTHROW {
  do_malloc_stats();
}

extern "C" PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) PERFTOOLS_NOTHROW {
  return do_mallopt(cmd, value);
}

#ifdef HAVE_STRUCT_MALLINFO
extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) PERFTOOLS_NOTHROW {
  return do_mallinfo();
}
#endif

#ifdef HAVE_STRUCT_MALLINFO2
extern "C" PERFTOOLS_DLL_DECL struct mallinfo2 tc_mallinfo2(void) PERFTOOLS_NOTHROW {
  return do_mallinfo();
}
#endif

extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) PERFTOOLS_NOTHROW {
  return MallocExtension::instance()->GetAllocatedSize(ptr);
}

extern "C" PERFTOOLS_DLL_DECL void* tc_malloc_skip_new_handler(size_t size) PERFTOOLS_NOTHROW {
  void* result = DebugAllocate(size, MallocBlock::kMallocType);
  tcmalloc::InvokeNewHook(result, size);
  return result;
}
gperftools-gperftools-2.18/src/emergency_malloc.cc000066400000000000000000000135371513545575200224420ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2014, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#include "config.h"

#include "emergency_malloc.h"

#include                       // for ENOMEM, errno
#include                      // for memset

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/low_level_alloc.h"
#include "base/memmap.h"
#include "base/spinlock.h"
#include "base/static_storage.h"
#include "internal_logging.h"

namespace tcmalloc {

ATTRIBUTE_VISIBILITY_HIDDEN char *emergency_arena_start;
ATTRIBUTE_VISIBILITY_HIDDEN uintptr_t emergency_arena_start_shifted;

static CACHELINE_ALIGNED SpinLock emergency_malloc_lock;
static char *emergency_arena_end;
static LowLevelAlloc::Arena *emergency_arena;

class EmergencyArenaPagesAllocator : public LowLevelAlloc::PagesAllocator {
  ~EmergencyArenaPagesAllocator() {}
  std::pair MapPages(size_t size) override {
    char *new_end = emergency_arena_end + size;
    if (new_end > emergency_arena_start + kEmergencyArenaSize) {
      RAW_LOG(FATAL, "Unable to allocate %zu bytes in emergency zone.", size);
    }
    char *rv = emergency_arena_end;
    emergency_arena_end = emergency_arena_start + kEmergencyArenaSize;
    return {static_cast(rv), emergency_arena_end - rv};
  }
  void UnMapPages(void *addr, size_t size) override {
    RAW_LOG(FATAL, "UnMapPages is not implemented for emergency arena");
  }
};

static void InitEmergencyMalloc(void) {
  auto [arena, success] = MapAnonymous(kEmergencyArenaSize * 2);
  CHECK_CONDITION(success);

  uintptr_t arena_ptr = reinterpret_cast(arena);
  uintptr_t ptr = (arena_ptr + kEmergencyArenaSize - 1) & ~(kEmergencyArenaSize-1);

  emergency_arena_end = emergency_arena_start = reinterpret_cast(ptr);

  static StaticStorage pages_allocator_place;
  EmergencyArenaPagesAllocator* allocator = pages_allocator_place.Construct();

  emergency_arena = LowLevelAlloc::NewArenaWithCustomAlloc(allocator);

  emergency_arena_start_shifted = reinterpret_cast(emergency_arena_start) >> kEmergencyArenaShift;

  uintptr_t head_unmap_size = ptr - arena_ptr;
  CHECK_CONDITION(head_unmap_size < kEmergencyArenaSize);
  if (head_unmap_size != 0) {
    // Note, yes, we ignore any potential, but ~impossible
    // failures. It should be harmless.
    (void)munmap(arena, ptr - arena_ptr);
  }

  uintptr_t tail_unmap_size = kEmergencyArenaSize - head_unmap_size;
  void *tail_start = reinterpret_cast(arena_ptr + head_unmap_size + kEmergencyArenaSize);
  // Failures are ignored. See above.
  (void)munmap(tail_start, tail_unmap_size);
}

ATTRIBUTE_VISIBILITY_HIDDEN void *EmergencyMalloc(size_t size) {
  SpinLockHolder l(&emergency_malloc_lock);

  if (emergency_arena_start == nullptr) {
    InitEmergencyMalloc();
    CHECK_CONDITION(emergency_arena_start != nullptr);
  }

  void *rv = LowLevelAlloc::AllocWithArena(size, emergency_arena);
  if (rv == nullptr) {
    errno = ENOMEM;
  }
  return rv;
}

ATTRIBUTE_VISIBILITY_HIDDEN void EmergencyFree(void *p) {
  SpinLockHolder l(&emergency_malloc_lock);
  CHECK_CONDITION(emergency_arena_start);
  LowLevelAlloc::Free(p);
}

ATTRIBUTE_VISIBILITY_HIDDEN size_t EmergencyAllocatedSize(const void *p) {
  CHECK_CONDITION(emergency_arena_start);
  return LowLevelAlloc::UsableSize(p);
}

ATTRIBUTE_VISIBILITY_HIDDEN void *EmergencyRealloc(void *_old_ptr, size_t new_size) {
  if (_old_ptr == nullptr) {
    return EmergencyMalloc(new_size);
  }
  if (new_size == 0) {
    EmergencyFree(_old_ptr);
    return nullptr;
  }
  SpinLockHolder l(&emergency_malloc_lock);
  CHECK_CONDITION(emergency_arena_start);

  char *old_ptr = static_cast(_old_ptr);
  CHECK_CONDITION(old_ptr <= emergency_arena_end);
  CHECK_CONDITION(emergency_arena_start <= old_ptr);

  // NOTE: we don't know previous size of old_ptr chunk. So instead
  // of trying to figure out right size of copied memory, we just
  // copy largest possible size. We don't care about being slow.
  size_t old_ptr_size = emergency_arena_end - old_ptr;
  size_t copy_size = (new_size < old_ptr_size) ? new_size : old_ptr_size;

  void *new_ptr = LowLevelAlloc::AllocWithArena(new_size, emergency_arena);
  if (new_ptr == nullptr) {
    errno = ENOMEM;
    return nullptr;
  }
  memcpy(new_ptr, old_ptr, copy_size);

  LowLevelAlloc::Free(old_ptr);
  return new_ptr;
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/emergency_malloc.h000066400000000000000000000051041513545575200222730ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2014, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef EMERGENCY_MALLOC_H
#define EMERGENCY_MALLOC_H
#include "config.h"

#include 

#include "base/basictypes.h"

namespace tcmalloc {

static constexpr uintptr_t kEmergencyArenaShift = 20+4; // 16 megs
static constexpr uintptr_t kEmergencyArenaSize = uintptr_t{1} << kEmergencyArenaShift;

ATTRIBUTE_VISIBILITY_HIDDEN extern char *emergency_arena_start;
ATTRIBUTE_VISIBILITY_HIDDEN extern uintptr_t emergency_arena_start_shifted;;

ATTRIBUTE_VISIBILITY_HIDDEN void *EmergencyMalloc(size_t size);
ATTRIBUTE_VISIBILITY_HIDDEN void EmergencyFree(void *p);
ATTRIBUTE_VISIBILITY_HIDDEN void *EmergencyRealloc(void *old_ptr, size_t new_size);
ATTRIBUTE_VISIBILITY_HIDDEN size_t EmergencyAllocatedSize(const void* p);

static inline bool IsEmergencyPtr(const void *_ptr) {
  uintptr_t ptr = reinterpret_cast(_ptr);
  return PREDICT_FALSE((ptr >> kEmergencyArenaShift) == emergency_arena_start_shifted)
    && emergency_arena_start_shifted;
}

} // namespace tcmalloc

#endif
gperftools-gperftools-2.18/src/gen_getpc.rb000077500000000000000000000147541513545575200211130ustar00rootroot00000000000000#!/usr/bin/env ruby
# Copyright (c) 2023, gperftools Contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

require 'digest'

# This is main logic. If you want to add new ucontext-to-pc accessor, add it here
def dwm!(d)
  d.template "NetBSD has really nice portable macros", :_UC_MACHINE_PC do |uc|
    "_UC_MACHINE_PC(#{uc})"
  end

  d.with_prefix "uc_mcontext." do
    # first arg is ifdef, second is field (with prefix prepended) and third is comment
    d.ifdef :REG_PC, "gregs[REG_PC]", "Solaris/x86"
    d.ifdef :REG_EIP, "gregs[REG_EIP]", "Linux/i386"
    d.ifdef :REG_RIP, "gregs[REG_RIP]", "Linux/amd64"
    d.field "sc_ip", "Linux/ia64"
    d.field "__pc", "Linux/loongarch64"
    d.field "pc", "Linux/{mips,aarch64}"
    d.ifdef :PT_NIP, "uc_regs->gregs[PT_NIP]", "Linux/ppc"
    d.ifdef :PT_NIP, "gp_regs[PT_NIP]", "Linux/ppc"
    d.ifdef :REG_PC, "__gregs[REG_PC]", "Linux/riscv"
    d.field "psw.addr", "Linux/s390"
    d.field "arm_pc", "Linux/arm (32-bit; legacy)"
    d.field "mc_eip", "FreeBSD/i386"
    d.field "mc_srr0", "FreeBSD/ppc"
    d.field "mc_rip", "FreeBSD/x86_64"
  end

  d.with_prefix "uc_mcontext->" do
    d.field "ss.eip", "OS X (i386, <=10.4)"
    d.field "__ss.__eip", "OS X (i386, >=10.5)"
    d.field "ss.rip", "OS X (x86_64)"
    d.field "__ss.__rip", "OS X (>=10.5 [untested])"
    d.field "ss.srr0", "OS X (ppc, ppc64 [untested])"
    d.field "__ss.__srr0", "OS X (>=10.5 [untested])"
    d.field "__ss.__pc", "OS X (arm64)"
  end

  d.field "sc_eip", "OpenBSD/i386"
  d.field "sc_rip", "OpenBSD/x86_64"
end

# this is generator logic
class Definer
  def initialize
    @prefix = ""
    @accessors = {}
    puts(< combos are
// automagically filtered out (via SFINAE).

// Each known case is represented as a template class. For SFINAE
// reasons we masquerade ucontext_t type behind U template
// parameter. And we also parameterize by parent class. This allows us
// to arrange all template instantiations in a single ordered chain of
// inheritance. See RawUCToPC below.

// Note, we do anticipate that most times exactly one of those access
// methods works. But we're prepared there could be several. In
// particular, according to previous comments Solaris/x86 also has
// REG_RIP defined, but it is somehow wrong. So we're careful about
// preserving specific order. We couldn't handle this "multiplicity"
// aspect in pure C++, so we use code generation.

namespace internal {

struct Empty {
#ifdef DEFINE_TRIVIAL_GET
#define HAVE_TRIVIAL_GET
  // special thing for stacktrace_generic_fp-inl which wants no-op case
  static void* Get(...) {
    return nullptr;
  }
#endif
};
HERE
  end

  def with_prefix(prefix)
    old_prefix = @prefix
    @prefix = @prefix.dup + prefix
    yield
  ensure
    @prefix = old_prefix
  end

  def ifdef define, field, comment
    field field, comment, define
  end

  def template comment, define = nil, &block
    field block, comment, define
  end

  def field field, comment, define = nil
    tmpl = if field.kind_of? Proc
             raise unless @prefix.empty?
             field
           else
             proc do |uc|
               "#{uc}->#{@prefix + field}"
             end
           end
    fingerprint = Digest::MD5.hexdigest(tmpl["%"] + "@" + comment)[0,8]

    maybe_open_ifdef = "\n#ifdef #{define}" if define
    maybe_close_ifdef = "\n#endif  // #{define}" if define

    raise "conflict!" if @accessors.include? fingerprint

    if define
      @accessors[fingerprint] = comment + " (with #ifdef #{define})"
    else
      @accessors[fingerprint] = comment
    end

    puts(<
struct get_#{fingerprint} : public P {
};#{maybe_open_ifdef}
template 
struct get_#{fingerprint}> : public P {
  static void* Get(const U* uc) {
    // #{comment}
    return (void*)(#{tmpl[:uc]});
  }
};#{maybe_close_ifdef}
HERE
  end

  def finalize!
    puts
    puts(<;"
      prev = "g_#{fingerprint}"
    end
    puts(<getpc-inl.h if you want to
// update. (And submit both files)

// What this file does? We have several possible ways of fetching PC
// (program counter) of signal's ucontext. We explicitly choose to
// avoid ifdef-ing specific OSes (or even specific versions), to
// increase our chances that stuff simply works. Comments below refer
// to OS/architecture combos for documentation purposes, but what
// works is what is used.

// How it does it? It uses lightweight C++ template magic where
// "wrong" ucontext_t{nullptr}-> combos are
// automagically filtered out (via SFINAE).

// Each known case is represented as a template class. For SFINAE
// reasons we masquerade ucontext_t type behind U template
// parameter. And we also parameterize by parent class. This allows us
// to arrange all template instantiations in a single ordered chain of
// inheritance. See RawUCToPC below.

// Note, we do anticipate that most times exactly one of those access
// methods works. But we're prepared there could be several. In
// particular, according to previous comments Solaris/x86 also has
// REG_RIP defined, but it is somehow wrong. So we're careful about
// preserving specific order. We couldn't handle this "multiplicity"
// aspect in pure C++, so we use code generation.

namespace internal {

struct Empty {
#ifdef DEFINE_TRIVIAL_GET
#define HAVE_TRIVIAL_GET
  // special thing for stacktrace_generic_fp-inl which wants no-op case
  static void* Get(...) {
    return nullptr;
  }
#endif
};

// NetBSD has really nice portable macros
template 
struct get_c47a30af : public P {
};
#ifdef _UC_MACHINE_PC
template 
struct get_c47a30af> : public P {
  static void* Get(const U* uc) {
    // NetBSD has really nice portable macros
    return (void*)(_UC_MACHINE_PC(uc));
  }
};
#endif  // _UC_MACHINE_PC

// Solaris/x86
template 
struct get_c4719e8d : public P {
};
#ifdef REG_PC
template 
struct get_c4719e8duc_mcontext.gregs[REG_PC])>> : public P {
  static void* Get(const U* uc) {
    // Solaris/x86
    return (void*)(uc->uc_mcontext.gregs[REG_PC]);
  }
};
#endif  // REG_PC

// Linux/i386
template 
struct get_278cba85 : public P {
};
#ifdef REG_EIP
template 
struct get_278cba85uc_mcontext.gregs[REG_EIP])>> : public P {
  static void* Get(const U* uc) {
    // Linux/i386
    return (void*)(uc->uc_mcontext.gregs[REG_EIP]);
  }
};
#endif  // REG_EIP

// Linux/amd64
template 
struct get_b49f2593 : public P {
};
#ifdef REG_RIP
template 
struct get_b49f2593uc_mcontext.gregs[REG_RIP])>> : public P {
  static void* Get(const U* uc) {
    // Linux/amd64
    return (void*)(uc->uc_mcontext.gregs[REG_RIP]);
  }
};
#endif  // REG_RIP

// Linux/ia64
template 
struct get_8fda99d3 : public P {
};
template 
struct get_8fda99d3uc_mcontext.sc_ip)>> : public P {
  static void* Get(const U* uc) {
    // Linux/ia64
    return (void*)(uc->uc_mcontext.sc_ip);
  }
};

// Linux/loongarch64
template 
struct get_4e9b682d : public P {
};
template 
struct get_4e9b682duc_mcontext.__pc)>> : public P {
  static void* Get(const U* uc) {
    // Linux/loongarch64
    return (void*)(uc->uc_mcontext.__pc);
  }
};

// Linux/{mips,aarch64}
template 
struct get_b94b7246 : public P {
};
template 
struct get_b94b7246uc_mcontext.pc)>> : public P {
  static void* Get(const U* uc) {
    // Linux/{mips,aarch64}
    return (void*)(uc->uc_mcontext.pc);
  }
};

// Linux/ppc
template 
struct get_d0eeceae : public P {
};
#ifdef PT_NIP
template 
struct get_d0eeceaeuc_mcontext.uc_regs->gregs[PT_NIP])>> : public P {
  static void* Get(const U* uc) {
    // Linux/ppc
    return (void*)(uc->uc_mcontext.uc_regs->gregs[PT_NIP]);
  }
};
#endif  // PT_NIP

// Linux/ppc
template 
struct get_a81f6801 : public P {
};
#ifdef PT_NIP
template 
struct get_a81f6801uc_mcontext.gp_regs[PT_NIP])>> : public P {
  static void* Get(const U* uc) {
    // Linux/ppc
    return (void*)(uc->uc_mcontext.gp_regs[PT_NIP]);
  }
};
#endif  // PT_NIP

// Linux/riscv
template 
struct get_24e794ef : public P {
};
#ifdef REG_PC
template 
struct get_24e794efuc_mcontext.__gregs[REG_PC])>> : public P {
  static void* Get(const U* uc) {
    // Linux/riscv
    return (void*)(uc->uc_mcontext.__gregs[REG_PC]);
  }
};
#endif  // REG_PC

// Linux/s390
template 
struct get_d9a75ed3 : public P {
};
template 
struct get_d9a75ed3uc_mcontext.psw.addr)>> : public P {
  static void* Get(const U* uc) {
    // Linux/s390
    return (void*)(uc->uc_mcontext.psw.addr);
  }
};

// Linux/arm (32-bit; legacy)
template 
struct get_07114491 : public P {
};
template 
struct get_07114491uc_mcontext.arm_pc)>> : public P {
  static void* Get(const U* uc) {
    // Linux/arm (32-bit; legacy)
    return (void*)(uc->uc_mcontext.arm_pc);
  }
};

// FreeBSD/i386
template 
struct get_9be162e6 : public P {
};
template 
struct get_9be162e6uc_mcontext.mc_eip)>> : public P {
  static void* Get(const U* uc) {
    // FreeBSD/i386
    return (void*)(uc->uc_mcontext.mc_eip);
  }
};

// FreeBSD/ppc
template 
struct get_2812b129 : public P {
};
template 
struct get_2812b129uc_mcontext.mc_srr0)>> : public P {
  static void* Get(const U* uc) {
    // FreeBSD/ppc
    return (void*)(uc->uc_mcontext.mc_srr0);
  }
};

// FreeBSD/x86_64
template 
struct get_5bb1da03 : public P {
};
template 
struct get_5bb1da03uc_mcontext.mc_rip)>> : public P {
  static void* Get(const U* uc) {
    // FreeBSD/x86_64
    return (void*)(uc->uc_mcontext.mc_rip);
  }
};

// OS X (i386, <=10.4)
template 
struct get_880f83fe : public P {
};
template 
struct get_880f83feuc_mcontext->ss.eip)>> : public P {
  static void* Get(const U* uc) {
    // OS X (i386, <=10.4)
    return (void*)(uc->uc_mcontext->ss.eip);
  }
};

// OS X (i386, >=10.5)
template 
struct get_92fcd89a : public P {
};
template 
struct get_92fcd89auc_mcontext->__ss.__eip)>> : public P {
  static void* Get(const U* uc) {
    // OS X (i386, >=10.5)
    return (void*)(uc->uc_mcontext->__ss.__eip);
  }
};

// OS X (x86_64)
template 
struct get_773e27c8 : public P {
};
template 
struct get_773e27c8uc_mcontext->ss.rip)>> : public P {
  static void* Get(const U* uc) {
    // OS X (x86_64)
    return (void*)(uc->uc_mcontext->ss.rip);
  }
};

// OS X (>=10.5 [untested])
template 
struct get_6627078a : public P {
};
template 
struct get_6627078auc_mcontext->__ss.__rip)>> : public P {
  static void* Get(const U* uc) {
    // OS X (>=10.5 [untested])
    return (void*)(uc->uc_mcontext->__ss.__rip);
  }
};

// OS X (ppc, ppc64 [untested])
template 
struct get_da992aca : public P {
};
template 
struct get_da992acauc_mcontext->ss.srr0)>> : public P {
  static void* Get(const U* uc) {
    // OS X (ppc, ppc64 [untested])
    return (void*)(uc->uc_mcontext->ss.srr0);
  }
};

// OS X (>=10.5 [untested])
template 
struct get_cce47a40 : public P {
};
template 
struct get_cce47a40uc_mcontext->__ss.__srr0)>> : public P {
  static void* Get(const U* uc) {
    // OS X (>=10.5 [untested])
    return (void*)(uc->uc_mcontext->__ss.__srr0);
  }
};

// OS X (arm64)
template 
struct get_0a082e42 : public P {
};
template 
struct get_0a082e42uc_mcontext->__ss.__pc)>> : public P {
  static void* Get(const U* uc) {
    // OS X (arm64)
    return (void*)(uc->uc_mcontext->__ss.__pc);
  }
};

// OpenBSD/i386
template 
struct get_3baa113a : public P {
};
template 
struct get_3baa113asc_eip)>> : public P {
  static void* Get(const U* uc) {
    // OpenBSD/i386
    return (void*)(uc->sc_eip);
  }
};

// OpenBSD/x86_64
template 
struct get_79f33851 : public P {
};
template 
struct get_79f33851sc_rip)>> : public P {
  static void* Get(const U* uc) {
    // OpenBSD/x86_64
    return (void*)(uc->sc_rip);
  }
};

inline void* RawUCToPC(const ucontext_t* uc) {
  // OpenBSD/x86_64
  using g_79f33851 = get_79f33851;
  // OpenBSD/i386
  using g_3baa113a = get_3baa113a;
  // OS X (arm64)
  using g_0a082e42 = get_0a082e42;
  // OS X (>=10.5 [untested])
  using g_cce47a40 = get_cce47a40;
  // OS X (ppc, ppc64 [untested])
  using g_da992aca = get_da992aca;
  // OS X (>=10.5 [untested])
  using g_6627078a = get_6627078a;
  // OS X (x86_64)
  using g_773e27c8 = get_773e27c8;
  // OS X (i386, >=10.5)
  using g_92fcd89a = get_92fcd89a;
  // OS X (i386, <=10.4)
  using g_880f83fe = get_880f83fe;
  // FreeBSD/x86_64
  using g_5bb1da03 = get_5bb1da03;
  // FreeBSD/ppc
  using g_2812b129 = get_2812b129;
  // FreeBSD/i386
  using g_9be162e6 = get_9be162e6;
  // Linux/arm (32-bit; legacy)
  using g_07114491 = get_07114491;
  // Linux/s390
  using g_d9a75ed3 = get_d9a75ed3;
  // Linux/riscv (with #ifdef REG_PC)
  using g_24e794ef = get_24e794ef;
  // Linux/ppc (with #ifdef PT_NIP)
  using g_a81f6801 = get_a81f6801;
  // Linux/ppc (with #ifdef PT_NIP)
  using g_d0eeceae = get_d0eeceae;
  // Linux/{mips,aarch64}
  using g_b94b7246 = get_b94b7246;
  // Linux/loongarch64
  using g_4e9b682d = get_4e9b682d;
  // Linux/ia64
  using g_8fda99d3 = get_8fda99d3;
  // Linux/amd64 (with #ifdef REG_RIP)
  using g_b49f2593 = get_b49f2593;
  // Linux/i386 (with #ifdef REG_EIP)
  using g_278cba85 = get_278cba85;
  // Solaris/x86 (with #ifdef REG_PC)
  using g_c4719e8d = get_c4719e8d;
  // NetBSD has really nice portable macros (with #ifdef _UC_MACHINE_PC)
  using g_c47a30af = get_c47a30af;
  return g_c47a30af::Get(uc);
}

}  // namespace internal
gperftools-gperftools-2.18/src/getpc.h000066400000000000000000000071011513545575200200670ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// This is an internal header file used by profiler.cc.  It defines
// the single (inline) function GetPC.  GetPC is used in a signal
// handler to figure out the instruction that was being executed when
// the signal-handler was triggered.
//
// To get this, we use the ucontext_t argument to the signal-handler
// callback, which holds the full context of what was going on when
// the signal triggered.  How to get from a ucontext_t to a Program
// Counter is OS-dependent.

#ifndef BASE_GETPC_H_
#define BASE_GETPC_H_

// Note, this file is used as part of ./configure so it cannot include
// "config.h" despite actually using HAVE_XYZ defines just below.

// On many linux systems, we may need _GNU_SOURCE to get access to
// the defined constants that define the register we want to see (eg
// REG_EIP).  Note this #define must come first!
#define _GNU_SOURCE 1

#ifdef HAVE_ASM_PTRACE_H
#include 
#endif
#if HAVE_SYS_UCONTEXT_H
#include 
#elif HAVE_UCONTEXT_H
#include        // for ucontext_t (and also mcontext_t)
#elif defined(HAVE_CYGWIN_SIGNAL_H)
#include 
typedef ucontext ucontext_t;
#endif

namespace tcmalloc {
namespace getpc {

// std::void_t is C++ 14. So we steal this from
// https://en.cppreference.com/w/cpp/types/void_t
template
struct make_void { typedef void type; };
template 
using void_t = typename make_void::type;

#include "getpc-inl.h"

}  // namespace getpc
}  // namespace tcmalloc

// If this doesn't compile, you need to figure out the right value for
// your system, and add it to the list above.
inline void* GetPC(const ucontext_t& signal_ucontext) {
  void* retval = tcmalloc::getpc::internal::RawUCToPC(&signal_ucontext);

#if defined(__s390__) && !defined(__s390x__)
  // Mask out the AMODE31 bit from the PC recorded in the context.
  retval = (void*)((unsigned long)retval & 0x7fffffffUL);
#endif

  return retval;
}

#endif  // BASE_GETPC_H_
gperftools-gperftools-2.18/src/gperftools/000077500000000000000000000000001513545575200210015ustar00rootroot00000000000000gperftools-gperftools-2.18/src/gperftools/heap-checker.h000066400000000000000000000130051513545575200234700ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// Copyright (c) 2024, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Note, this file contains stub of HeapLeakChecker API that we used
// to implement. Below is merely a stub, empty no-op
// implementation. It only exists to maintain some degree of backwards
// API and ABI compatibility. If you're using this file, please
// consider switching to sanitizers.
#ifndef BASE_HEAP_CHECKER_H_
#define BASE_HEAP_CHECKER_H_

#include 
#include 

#include 

#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif

// The class is thread-safe with respect to all the provided static methods,
// as well as HeapLeakChecker objects: they can be accessed by multiple threads.
class PERFTOOLS_DLL_DECL HeapLeakChecker {
 public:
  static bool IsActive();
  static HeapLeakChecker* GlobalChecker();
  static bool NoGlobalLeaks();
  static void CancelGlobalCheck();

  explicit HeapLeakChecker(const char *name);

  ~HeapLeakChecker();

  bool NoLeaks() { return DoNoLeaks(DO_NOT_SYMBOLIZE); }

  bool QuickNoLeaks()  { return NoLeaks(); }
  bool BriefNoLeaks()  { return NoLeaks(); }
  bool SameHeap()      { return NoLeaks(); }
  bool QuickSameHeap() { return NoLeaks(); }
  bool BriefSameHeap() { return NoLeaks(); }

  // Note, original code had ssize_t, but windows lacks it. So to keep
  // things easier and more portable we're converting to ptrdiff_t.
  // It is same in practice.
  ptrdiff_t BytesLeaked() const;
  ptrdiff_t ObjectsLeaked() const;

  class Disabler {
   public:
    Disabler();
    ~Disabler();
   private:
    Disabler(const Disabler&);        // disallow copy
    void operator=(const Disabler&);  // and assign
  };

  template 
  static T* IgnoreObject(T* ptr) {
    DoIgnoreObject(static_cast(const_cast(ptr)));
    return ptr;
  }

  static void UnIgnoreObject(const void* ptr);

private:
  enum ShouldSymbolize { SYMBOLIZE, DO_NOT_SYMBOLIZE };

  bool DoNoLeaks(ShouldSymbolize should_symbolize);
  static void DoIgnoreObject(const void* ptr);

  void* _ex_lock_;
  const char* name_;

  void* start_snapshot_;

  bool has_checked_;
  ptrdiff_t inuse_bytes_increase_;
  ptrdiff_t inuse_allocs_increase_;
                                   // for this checker
  bool keep_profiles_;

  HeapLeakChecker(const HeapLeakChecker&);
  void operator=(const HeapLeakChecker&);
};


// Holds a pointer that will not be traversed by the heap checker.
// Contrast with HeapLeakChecker::IgnoreObject(o), in which o and
// all objects reachable from o are ignored by the heap checker.
template 
class HiddenPointer {
 public:
  explicit HiddenPointer(T* t)
      : masked_t_(reinterpret_cast(t) ^ kHideMask) {
  }
  // Returns unhidden pointer.  Be careful where you save the result.
  T* get() const { return reinterpret_cast(masked_t_ ^ kHideMask); }

 private:
  // Arbitrary value, but not such that xor'ing with it is likely
  // to map one valid pointer to another valid pointer:
  static const uintptr_t kHideMask =
      static_cast(0xF03A5F7BF03A5F7Bll);
  uintptr_t masked_t_;
};

// A class that exists solely to run its destructor.  This class should not be
// used directly, but instead by the REGISTER_HEAPCHECK_CLEANUP macro below.
class PERFTOOLS_DLL_DECL HeapCleaner {
 public:
  typedef void (*void_function)(void);
  HeapCleaner(void_function f);
  static void RunHeapCleanups();
 private:
  static std::vector* heap_cleanups_;
};

// A macro to declare module heap check cleanup tasks
// (they run only if we are doing heap leak checking.)
// 'body' should be the cleanup code to run.  'name' doesn't matter,
// but must be unique amongst all REGISTER_HEAPCHECK_CLEANUP calls.
#define REGISTER_HEAPCHECK_CLEANUP(name, body)  \
  namespace { \
  void heapcheck_cleanup_##name() { body; } \
  static HeapCleaner heapcheck_cleaner_##name(&heapcheck_cleanup_##name); \
  }

#endif  // BASE_HEAP_CHECKER_H_
gperftools-gperftools-2.18/src/gperftools/heap-profiler.h000066400000000000000000000077161513545575200237220ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* Copyright (c) 2005, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Sanjay Ghemawat
 *
 * Module for heap-profiling.
 *
 * For full(er) information, see docs/heapprofile.html
 *
 * This module can be linked into your program with
 * no slowdown caused by this unless you activate the profiler
 * using one of the following methods:
 *
 *    1. Before starting the program, set the environment variable
 *       "HEAPPROFILE" to be the name of the file to which the profile
 *       data should be written.
 *
 *    2. Programmatically, start and stop the profiler using the
 *       routines "HeapProfilerStart(filename)" and "HeapProfilerStop()".
 *
 */

#ifndef BASE_HEAP_PROFILER_H_
#define BASE_HEAP_PROFILER_H_

#include 

/* Annoying stuff for windows; makes sure clients can import these functions */
#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif

/* All this code should be usable from within C apps. */
#ifdef __cplusplus
extern "C" {
#endif

/* Start profiling and arrange to write profile data to file names
 * of the form: "prefix.0000", "prefix.0001", ...
 */
PERFTOOLS_DLL_DECL void HeapProfilerStart(const char* prefix);

/* Returns non-zero if we are currently profiling the heap.  (Returns
 * an int rather than a bool so it's usable from C.)  This is true
 * between calls to HeapProfilerStart() and HeapProfilerStop(), and
 * also if the program has been run with HEAPPROFILER, or some other
 * way to turn on whole-program profiling.
 */
PERFTOOLS_DLL_DECL int IsHeapProfilerRunning();

/* Stop heap profiling.  Can be restarted again with HeapProfilerStart(),
 * but the currently accumulated profiling information will be cleared.
 */
PERFTOOLS_DLL_DECL void HeapProfilerStop();

/* Dump a profile now - can be used for dumping at a hopefully
 * quiescent state in your program, in order to more easily track down
 * memory leaks. Will include the reason in the logged message
 */
PERFTOOLS_DLL_DECL void HeapProfilerDump(const char *reason);

/* Generate current heap profiling information.
 * Returns an empty string when heap profiling is not active.
 * The returned pointer is a '\0'-terminated string allocated using malloc()
 * and should be free()-ed as soon as the caller does not need it anymore.
 */
PERFTOOLS_DLL_DECL char* GetHeapProfile();

#ifdef __cplusplus
}  // extern "C"
#endif

#endif  /* BASE_HEAP_PROFILER_H_ */
gperftools-gperftools-2.18/src/gperftools/malloc_extension.h000066400000000000000000000462321513545575200245240ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 
//
// Extra extensions exported by some malloc implementations.  These
// extensions are accessed through a virtual base class so an
// application can link against a malloc that does not implement these
// extensions, and it will get default versions that do nothing.
//
// NOTE FOR C USERS: If you wish to use this functionality from within
// a C program, see malloc_extension_c.h.

#ifndef BASE_MALLOC_EXTENSION_H_
#define BASE_MALLOC_EXTENSION_H_

#include 
// I can't #include config.h in this public API file, but I should
// really use configure (and make malloc_extension.h a .in file) to
// figure out if the system has stdint.h or not.  But I'm lazy, so
// for now I'm assuming it's a problem only with MSVC.
#ifndef _MSC_VER
#include 
#endif
#include 
#include 

// Annoying stuff for windows -- makes sure clients can import these functions
#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif

static const int kMallocHistogramSize = 64;

// One day, we could support other types of writers (perhaps for C?)
typedef std::string MallocExtensionWriter;

namespace base {
struct MallocRange;
}

// Interface to a pluggable system allocator.
class PERFTOOLS_DLL_DECL SysAllocator {
 public:
  SysAllocator() {
  }
  virtual ~SysAllocator();

  // Allocates "size"-byte of memory from system aligned with "alignment".
  // Returns nullptr if failed. Otherwise, the returned pointer p up to and
  // including (p + actual_size -1) have been allocated.
  virtual void* Alloc(size_t size, size_t *actual_size, size_t alignment) = 0;
};

// The default implementations of the following routines do nothing.
// All implementations should be thread-safe; the current one
// (TCMallocImplementation) is.
class PERFTOOLS_DLL_DECL MallocExtension {
 public:
  virtual ~MallocExtension();

  // DEPRECATED. No-op.
  static void Initialize();

  // See "verify_memory.h" to see what these routines do
  virtual bool VerifyAllMemory();
  virtual bool VerifyNewMemory(const void* p);
  virtual bool VerifyArrayNewMemory(const void* p);
  virtual bool VerifyMallocMemory(const void* p);
  virtual bool MallocMemoryStats(int* blocks, size_t* total,
                                 int histogram[kMallocHistogramSize]);

  // Get a human readable description of the following malloc data structures.
  // - Total inuse memory by application.
  // - Free memory(thread, central and page heap),
  // - Freelist of central cache, each class.
  // - Page heap freelist.
  // The state is stored as a null-terminated string
  // in a prefix of "buffer[0,buffer_length-1]".
  // REQUIRES: buffer_length > 0.
  virtual void GetStats(char* buffer, int buffer_length);

  // Outputs to "writer" a sample of live objects and the stack traces
  // that allocated these objects.  The format of the returned output
  // is equivalent to the output of the heap profiler and can
  // therefore be passed to "pprof". This function is equivalent to
  // ReadStackTraces. The main difference is that this function returns
  // serialized data appropriately formatted for use by the pprof tool.
  //
  // Since gperftools 2.8 heap samples are not de-duplicated by the
  // library anymore.
  //
  // NOTE: by default, tcmalloc does not do any heap sampling, and this
  //       function will always return an empty sample.  To get useful
  //       data from GetHeapSample, you must also set the environment
  //       variable TCMALLOC_SAMPLE_PARAMETER to a value such as 524288.
  virtual void GetHeapSample(MallocExtensionWriter* writer);

  // Outputs to "writer" the stack traces that caused growth in the
  // address space size.  The format of the returned output is
  // equivalent to the output of the heap profiler and can therefore
  // be passed to "pprof". This function is equivalent to
  // ReadHeapGrowthStackTraces. The main difference is that this function
  // returns serialized data appropriately formatted for use by the
  // pprof tool.  (This does not depend on, or require,
  // TCMALLOC_SAMPLE_PARAMETER.)
  virtual void GetHeapGrowthStacks(MallocExtensionWriter* writer);

  // Invokes func(arg, range) for every controlled memory
  // range.  *range is filled in with information about the range.
  //
  // This is a best-effort interface useful only for performance
  // analysis.  The implementation may not call func at all.
  typedef void (RangeFunction)(void*, const base::MallocRange*);
  virtual void Ranges(void* arg, RangeFunction func);

  // -------------------------------------------------------------------
  // Control operations for getting and setting malloc implementation
  // specific parameters.  Some currently useful properties:
  //
  // generic
  // -------
  // "generic.current_allocated_bytes"
  //      Number of bytes currently allocated by application
  //      This property is not writable.
  //
  // "generic.heap_size"
  //      Number of bytes in the heap ==
  //            current_allocated_bytes +
  //            fragmentation +
  //            freed memory regions
  //      This property is not writable.
  //
  //  "generic.total_physical_bytes"
  //      Estimate of total bytes of the physical memory usage by the
  //      allocator ==
  //            current_allocated_bytes +
  //            fragmentation +
  //            metadata
  //      This property is not writable.
  //
  // tcmalloc
  // --------
  // "tcmalloc.max_total_thread_cache_bytes"
  //      Upper limit on total number of bytes stored across all
  //      per-thread caches.  Default: 32MB.
  //
  // "tcmalloc.min_per_thread_cache_bytes"
  //      Lower limit on total number of bytes stored per-thread cache.
  //      Default: 512kB.
  //      Note that this property only shows effect if per-thread cache
  //      calculated using tcmalloc.max_total_thread_cache_bytes ended up being
  //      less than tcmalloc.min_per_thread_cache_bytes.
  //
  // "tcmalloc.current_total_thread_cache_bytes"
  //      Number of bytes used across all thread caches.
  //      This property is not writable.
  //
  // "tcmalloc.central_cache_free_bytes"
  //      Number of free bytes in the central cache that have been
  //      assigned to size classes. They always count towards virtual
  //      memory usage, and unless the underlying memory is swapped out
  //      by the OS, they also count towards physical memory usage.
  //      This property is not writable.
  //
  // "tcmalloc.transfer_cache_free_bytes"
  //      Number of free bytes that are waiting to be transfered between
  //      the central cache and a thread cache. They always count
  //      towards virtual memory usage, and unless the underlying memory
  //      is swapped out by the OS, they also count towards physical
  //      memory usage. This property is not writable.
  //
  // "tcmalloc.thread_cache_free_bytes"
  //      Number of free bytes in thread caches. They always count
  //      towards virtual memory usage, and unless the underlying memory
  //      is swapped out by the OS, they also count towards physical
  //      memory usage. This property is not writable.
  //
  // "tcmalloc.pageheap_free_bytes"
  //      Number of bytes in free, mapped pages in page heap.  These
  //      bytes can be used to fulfill allocation requests.  They
  //      always count towards virtual memory usage, and unless the
  //      underlying memory is swapped out by the OS, they also count
  //      towards physical memory usage.  This property is not writable.
  //
  // "tcmalloc.pageheap_unmapped_bytes"
  //        Number of bytes in free, unmapped pages in page heap.
  //        These are bytes that have been released back to the OS,
  //        possibly by one of the MallocExtension "Release" calls.
  //        They can be used to fulfill allocation requests, but
  //        typically incur a page fault.  They always count towards
  //        virtual memory usage, and depending on the OS, typically
  //        do not count towards physical memory usage.  This property
  //        is not writable.
  // -------------------------------------------------------------------

  // Get the named "property"'s value.  Returns true if the property
  // is known.  Returns false if the property is not a valid property
  // name for the current malloc implementation.
  // REQUIRES: property != nullptr; value != nullptr
  virtual bool GetNumericProperty(const char* property, size_t* value);

  // Set the named "property"'s value.  Returns true if the property
  // is known and writable.  Returns false if the property is not a
  // valid property name for the current malloc implementation, or
  // is not writable.
  // REQUIRES: property != nullptr
  virtual bool SetNumericProperty(const char* property, size_t value);

  // Mark the current thread as "idle".  This routine may optionally
  // be called by threads as a hint to the malloc implementation that
  // any thread-specific resources should be released.  Note: this may
  // be an expensive routine, so it should not be called too often.
  //
  // Also, if the code that calls this routine will go to sleep for
  // a while, it should take care to not allocate anything between
  // the call to this routine and the beginning of the sleep.
  //
  // Most malloc implementations ignore this routine.
  virtual void MarkThreadIdle();

  // Mark the current thread as "busy".  This routine should be
  // called after MarkThreadIdle() if the thread will now do more
  // work.  If this method is not called, performance may suffer.
  //
  // Most malloc implementations ignore this routine.
  virtual void MarkThreadBusy();

  // Gets the system allocator used by the malloc extension instance. Returns
  // nullptr for malloc implementations that do not support pluggable system
  // allocators.
  virtual SysAllocator* GetSystemAllocator();

  // Sets the system allocator to the specified.
  //
  // Users could register their own system allocators for malloc implementation
  // that supports pluggable system allocators, such as TCMalloc, by doing:
  //   alloc = new MyOwnSysAllocator();
  //   MallocExtension::instance()->SetSystemAllocator(alloc);
  // It's up to users whether to fall back (recommended) to the default
  // system allocator (use GetSystemAllocator() above) or not. The caller is
  // responsible to any necessary locking.
  // See tcmalloc/system-alloc.h for the interface and
  //     tcmalloc/memfs_malloc.cc for the examples.
  //
  // It's a no-op for malloc implementations that do not support pluggable
  // system allocators.
  virtual void SetSystemAllocator(SysAllocator *a);

  // Try to release num_bytes of free memory back to the operating
  // system for reuse.  Use this extension with caution -- to get this
  // memory back may require faulting pages back in by the OS, and
  // that may be slow.  (Currently only implemented in tcmalloc.)
  virtual void ReleaseToSystem(size_t num_bytes);

  // Same as ReleaseToSystem() but release as much memory as possible.
  virtual void ReleaseFreeMemory();

  // Sets the rate at which we release unused memory to the system.
  // Zero means we never release memory back to the system.  Increase
  // this flag to return memory faster; decrease it to return memory
  // slower.  Reasonable rates are in the range [0,10].  (Currently
  // only implemented in tcmalloc).
  virtual void SetMemoryReleaseRate(double rate);

  // Gets the release rate.  Returns a value < 0 if unknown.
  virtual double GetMemoryReleaseRate();

  // Returns the estimated number of bytes that will be allocated for
  // a request of "size" bytes.  This is an estimate: an allocation of
  // SIZE bytes may reserve more bytes, but will never reserve less.
  // (Currently only implemented in tcmalloc, other implementations
  // always return SIZE.)
  // This is equivalent to malloc_good_size() in OS X.
  virtual size_t GetEstimatedAllocatedSize(size_t size);

  // Returns the actual number N of bytes reserved by tcmalloc for the
  // pointer p.  The client is allowed to use the range of bytes
  // [p, p+N) in any way it wishes (i.e. N is the "usable size" of this
  // allocation).  This number may be equal to or greater than the number
  // of bytes requested when p was allocated.
  // p must have been allocated by this malloc implementation,
  // must not be an interior pointer -- that is, must be exactly
  // the pointer returned to by malloc() et al., not some offset
  // from that -- and should not have been freed yet.  p may be nullptr.
  // (Currently only implemented in tcmalloc; other implementations
  // will return 0.)
  // This is equivalent to malloc_size() in OS X, malloc_usable_size()
  // in glibc, and _msize() for windows.
  virtual size_t GetAllocatedSize(const void* p);

  // Returns kOwned if this malloc implementation allocated the memory
  // pointed to by p, or kNotOwned if some other malloc implementation
  // allocated it or p is nullptr.  May also return kUnknownOwnership if
  // the malloc implementation does not keep track of ownership.
  // REQUIRES: p must be a value returned from a previous call to
  // malloc(), calloc(), realloc(), memalign(), posix_memalign(),
  // valloc(), pvalloc(), new, or new[], and must refer to memory that
  // is currently allocated (so, for instance, you should not pass in
  // a pointer after having called free() on it).
  enum Ownership {
    // NOTE: Enum values MUST be kept in sync with the version in
    // malloc_extension_c.h
    kUnknownOwnership = 0,
    kOwned,
    kNotOwned
  };
  virtual Ownership GetOwnership(const void* p);

  // The current malloc implementation.  Always non-nullptr.
  static MallocExtension* instance();

  // DEPRECATED. Internal.
  static void Register(MallocExtension* implementation);

  // Returns detailed information about malloc's freelists. For each list,
  // return a FreeListInfo:
  struct FreeListInfo {
    size_t min_object_size;
    size_t max_object_size;
    size_t total_bytes_free;
    const char* type;
  };
  // Each item in the vector refers to a different freelist. The lists
  // are identified by the range of allocations that objects in the
  // list can satisfy ([min_object_size, max_object_size]) and the
  // type of freelist (see below). The current size of the list is
  // returned in total_bytes_free (which count against a processes
  // resident and virtual size).
  //
  // Currently supported types are:
  //
  // "tcmalloc.page{_unmapped}" - tcmalloc's page heap. An entry for each size
  //          class in the page heap is returned. Bytes in "page_unmapped"
  //          are no longer backed by physical memory and do not count against
  //          the resident size of a process.
  //
  // "tcmalloc.large{_unmapped}" - tcmalloc's list of objects larger
  //          than the largest page heap size class. Only one "large"
  //          entry is returned. There is no upper-bound on the size
  //          of objects in the large free list; this call returns
  //          kint64max for max_object_size.  Bytes in
  //          "large_unmapped" are no longer backed by physical memory
  //          and do not count against the resident size of a process.
  //
  // "tcmalloc.central" - tcmalloc's central free-list. One entry per
  //          size-class is returned. Never unmapped.
  //
  // "debug.free_queue" - free objects queued by the debug allocator
  //                      and not returned to tcmalloc.
  //
  // "tcmalloc.thread" - tcmalloc's per-thread caches. Never unmapped.
  virtual void GetFreeListSizes(std::vector* v);

  // Get a list of stack traces of sampled allocation points.  Returns
  // a pointer to a "new[]-ed" result array, and stores the sample
  // period in "sample_period".
  //
  // The state is stored as a sequence of adjacent entries
  // in the returned array.  Each entry has the following form:
  //    uintptr_t count;        // Number of objects with following trace
  //    uintptr_t size;         // Total size of objects with following trace
  //    uintptr_t depth;        // Number of PC values in stack trace
  //    void*     stack[depth]; // PC values that form the stack trace
  //
  // The list of entries is terminated by a "count" of 0.
  //
  // It is the responsibility of the caller to "delete[]" the returned array.
  //
  // May return nullptr to indicate no results.
  //
  // This is an internal extension.  Callers should use the more
  // convenient "GetHeapSample(string*)" method defined above.
  virtual void** ReadStackTraces(int* sample_period);

  // Like ReadStackTraces(), but returns stack traces that caused growth
  // in the address space size.
  virtual void** ReadHeapGrowthStackTraces();

  // Returns the size in bytes of the calling threads cache.
  virtual size_t GetThreadCacheSize();

  // Note, as of gperftools 3.11 it is identical to
  // MarkThreadIdle. See github issue #880
  virtual void MarkThreadTemporarilyIdle();
};

namespace base {

// Information passed per range.  More fields may be added later.
struct MallocRange {
  enum Type {
    INUSE,                // Application is using this range
    FREE,                 // Range is currently free
    UNMAPPED,             // Backing physical memory has been returned to the OS
    UNKNOWN
    // More enum values may be added in the future
  };

  uintptr_t address;    // Address of range
  size_t length;        // Byte length of range
  Type type;            // Type of this range
  double fraction;      // Fraction of range that is being used (0 if !INUSE)

  // Perhaps add the following:
  // - stack trace if this range was sampled
  // - heap growth stack trace if applicable to this range
  // - age when allocated (for inuse) or freed (if not in use)
};

} // namespace base

#endif  // BASE_MALLOC_EXTENSION_H_
gperftools-gperftools-2.18/src/gperftools/malloc_extension_c.h000066400000000000000000000103671513545575200250260ustar00rootroot00000000000000/* Copyright (c) 2008, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * --
 * Author: Craig Silverstein
 *
 * C shims for the C++ malloc_extension.h.  See malloc_extension.h for
 * details.  Note these C shims always work on
 * MallocExtension::instance(); it is not possible to have more than
 * one MallocExtension object in C applications.
 */

#ifndef _MALLOC_EXTENSION_C_H_
#define _MALLOC_EXTENSION_C_H_

#include 
#include 

/* Annoying stuff for windows -- makes sure clients can import these fns */
#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define kMallocExtensionHistogramSize 64

PERFTOOLS_DLL_DECL int MallocExtension_VerifyAllMemory(void);
PERFTOOLS_DLL_DECL int MallocExtension_VerifyNewMemory(const void* p);
PERFTOOLS_DLL_DECL int MallocExtension_VerifyArrayNewMemory(const void* p);
PERFTOOLS_DLL_DECL int MallocExtension_VerifyMallocMemory(const void* p);
PERFTOOLS_DLL_DECL int MallocExtension_MallocMemoryStats(int* blocks, size_t* total,
                                      int histogram[kMallocExtensionHistogramSize]);
PERFTOOLS_DLL_DECL void MallocExtension_GetStats(char* buffer, int buffer_length);

/* TODO(csilvers): write a C version of these routines, that perhaps
 * takes a function ptr and a void *.
 */
/* void MallocExtension_GetHeapSample(string* result); */
/* void MallocExtension_GetHeapGrowthStacks(string* result); */

PERFTOOLS_DLL_DECL int MallocExtension_GetNumericProperty(const char* property, size_t* value);
PERFTOOLS_DLL_DECL int MallocExtension_SetNumericProperty(const char* property, size_t value);
PERFTOOLS_DLL_DECL void MallocExtension_MarkThreadIdle(void);
PERFTOOLS_DLL_DECL void MallocExtension_MarkThreadBusy(void);
PERFTOOLS_DLL_DECL void MallocExtension_ReleaseToSystem(size_t num_bytes);
PERFTOOLS_DLL_DECL void MallocExtension_ReleaseFreeMemory(void);
PERFTOOLS_DLL_DECL void MallocExtension_SetMemoryReleaseRate(double rate);
PERFTOOLS_DLL_DECL double MallocExtension_GetMemoryReleaseRate(void);
PERFTOOLS_DLL_DECL size_t MallocExtension_GetEstimatedAllocatedSize(size_t size);
PERFTOOLS_DLL_DECL size_t MallocExtension_GetAllocatedSize(const void* p);
PERFTOOLS_DLL_DECL size_t MallocExtension_GetThreadCacheSize(void);
PERFTOOLS_DLL_DECL void MallocExtension_MarkThreadTemporarilyIdle(void);

/*
 * NOTE: These enum values MUST be kept in sync with the version in
 *       malloc_extension.h
 */
typedef enum {
  MallocExtension_kUnknownOwnership = 0,
  MallocExtension_kOwned,
  MallocExtension_kNotOwned
} MallocExtension_Ownership;

PERFTOOLS_DLL_DECL MallocExtension_Ownership MallocExtension_GetOwnership(const void* p);

#ifdef __cplusplus
}   /* extern "C" */
#endif

#endif /* _MALLOC_EXTENSION_C_H_ */
gperftools-gperftools-2.18/src/gperftools/malloc_hook.h000066400000000000000000000210271513545575200234430ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// Some of our malloc implementations can invoke the following hooks whenever
// memory is allocated or deallocated.  MallocHook is thread-safe, and things
// you do before calling AddFooHook(MyHook) are visible to any resulting calls
// to MyHook.  Hooks must be thread-safe.  If you write:
//
//   CHECK(MallocHook::AddNewHook(&MyNewHook));
//
// MyNewHook will be invoked in subsequent calls in the current thread, but
// there are no guarantees on when it might be invoked in other threads.
//
// There are a limited number of slots available for each hook type.  Add*Hook
// will return false if there are no slots available.  Remove*Hook will return
// false if the given hook was not already installed.
//
// The order in which individual hooks are called in Invoke*Hook is undefined.
//
// It is safe for a hook to remove itself within Invoke*Hook and add other
// hooks.  Any hooks added inside a hook invocation (for the same hook type)
// will not be invoked for the current invocation.
//
// One important user of these hooks is the heap profiler.
//
// NOTE FOR C USERS: If you want to use malloc_hook functionality from
// a C program, #include malloc_hook_c.h instead of this file.

#ifndef _MALLOC_HOOK_H_
#define _MALLOC_HOOK_H_

#include 
#include 
extern "C" {
#include "malloc_hook_c.h"  // a C version of the malloc_hook interface
}

// Annoying stuff for windows -- makes sure clients can import these functions
#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif

// The C++ methods below call the C version (MallocHook_*), and thus
// convert between an int and a bool.  Windows complains about this
// (a "performance warning") which we don't care about, so we suppress.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4800)
#endif

// Note: malloc_hook_c.h defines MallocHook_*Hook and
// MallocHook_{Add,Remove}*Hook.  The version of these inside the MallocHook
// class are defined in terms of the malloc_hook_c version.  See malloc_hook_c.h
// for details of these types/functions.

class PERFTOOLS_DLL_DECL MallocHook {
 public:
  // The NewHook is invoked whenever an object is allocated.
  // It may be passed nullptr if the allocator returned nullptr.
  typedef MallocHook_NewHook NewHook;
  inline static bool AddNewHook(NewHook hook) {
    return MallocHook_AddNewHook(hook);
  }
  inline static bool RemoveNewHook(NewHook hook) {
    return MallocHook_RemoveNewHook(hook);
  }
  // The DeleteHook is invoked whenever an object is deallocated.
  // It may be passed nullptr if the caller is trying to delete nullptr.
  typedef MallocHook_DeleteHook DeleteHook;
  inline static bool AddDeleteHook(DeleteHook hook) {
    return MallocHook_AddDeleteHook(hook);
  }
  inline static bool RemoveDeleteHook(DeleteHook hook) {
    return MallocHook_RemoveDeleteHook(hook);
  }
  inline static void InvokeDeleteHook(const void* p);

  // Get the current stack trace.  Try to skip all routines up to and
  // and including the caller of tcmalloc::Invoke*.
  // Use "skip_count" (similarly to GetStackTrace from stacktrace.h)
  // as a hint about how many routines to skip if better information
  // is not available.
  inline static int GetCallerStackTrace(void** result, int max_depth,
                                        int skip_count) {
    return MallocHook_GetCallerStackTrace(result, max_depth, skip_count);
  }

  // Unhooked versions of mmap() and munmap().   These should be used
  // only by experts, since they bypass heapchecking, etc.
  // Note: These do not run hooks, but they still use the MmapReplacement
  // and MunmapReplacement.
  static void* UnhookedMMap(void *start, size_t length, int prot, int flags,
                            int fd, off_t offset);
  static int UnhookedMUnmap(void *start, size_t length);

  // The following are DEPRECATED. Also all mmap and sbrk
  // hooks/prehooks/replacement hooks are no-ops.

  typedef MallocHook_PreMmapHook PreMmapHook;
  inline static bool AddPreMmapHook(PreMmapHook hook) {
    return MallocHook_AddPreMmapHook(hook);
  }
  inline static bool RemovePreMmapHook(PreMmapHook hook) {
    return MallocHook_RemovePreMmapHook(hook);
  }

  typedef MallocHook_MmapReplacement MmapReplacement;
  inline static bool SetMmapReplacement(MmapReplacement hook) {
    return MallocHook_SetMmapReplacement(hook);
  }
  inline static bool RemoveMmapReplacement(MmapReplacement hook) {
    return MallocHook_RemoveMmapReplacement(hook);
  }


  typedef MallocHook_MmapHook MmapHook;
  inline static bool AddMmapHook(MmapHook hook) {
    return MallocHook_AddMmapHook(hook);
  }
  inline static bool RemoveMmapHook(MmapHook hook) {
    return MallocHook_RemoveMmapHook(hook);
  }

  typedef MallocHook_MunmapReplacement MunmapReplacement;
  inline static bool SetMunmapReplacement(MunmapReplacement hook) {
    return MallocHook_SetMunmapReplacement(hook);
  }
  inline static bool RemoveMunmapReplacement(MunmapReplacement hook) {
    return MallocHook_RemoveMunmapReplacement(hook);
  }

  typedef MallocHook_MunmapHook MunmapHook;
  inline static bool AddMunmapHook(MunmapHook hook) {
    return MallocHook_AddMunmapHook(hook);
  }
  inline static bool RemoveMunmapHook(MunmapHook hook) {
    return MallocHook_RemoveMunmapHook(hook);
  }

  typedef MallocHook_MremapHook MremapHook;
  inline static bool AddMremapHook(MremapHook hook) {
    return MallocHook_AddMremapHook(hook);
  }
  inline static bool RemoveMremapHook(MremapHook hook) {
    return MallocHook_RemoveMremapHook(hook);
  }

  typedef MallocHook_PreSbrkHook PreSbrkHook;
  inline static bool AddPreSbrkHook(PreSbrkHook hook) {
    return MallocHook_AddPreSbrkHook(hook);
  }
  inline static bool RemovePreSbrkHook(PreSbrkHook hook) {
    return MallocHook_RemovePreSbrkHook(hook);
  }

  typedef MallocHook_SbrkHook SbrkHook;
  inline static bool AddSbrkHook(SbrkHook hook) {
    return MallocHook_AddSbrkHook(hook);
  }
  inline static bool RemoveSbrkHook(SbrkHook hook) {
    return MallocHook_RemoveSbrkHook(hook);
  }

  inline static NewHook SetNewHook(NewHook hook) {
    return MallocHook_SetNewHook(hook);
  }

  inline static DeleteHook SetDeleteHook(DeleteHook hook) {
    return MallocHook_SetDeleteHook(hook);
  }

  inline static PreMmapHook SetPreMmapHook(PreMmapHook hook) {
    return MallocHook_SetPreMmapHook(hook);
  }

  inline static MmapHook SetMmapHook(MmapHook hook) {
    return MallocHook_SetMmapHook(hook);
  }

  inline static MunmapHook SetMunmapHook(MunmapHook hook) {
    return MallocHook_SetMunmapHook(hook);
  }

  inline static MremapHook SetMremapHook(MremapHook hook) {
    return MallocHook_SetMremapHook(hook);
  }

  inline static PreSbrkHook SetPreSbrkHook(PreSbrkHook hook) {
    return MallocHook_SetPreSbrkHook(hook);
  }

  inline static SbrkHook SetSbrkHook(SbrkHook hook) {
    return MallocHook_SetSbrkHook(hook);
  }
  // End of DEPRECATED methods.
};

#ifdef _MSC_VER
#pragma warning(pop)
#endif


#endif /* _MALLOC_HOOK_H_ */
gperftools-gperftools-2.18/src/gperftools/malloc_hook_c.h000066400000000000000000000153661513545575200237560ustar00rootroot00000000000000/* Copyright (c) 2008, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * --
 * Author: Craig Silverstein
 *
 * C shims for the C++ malloc_hook.h.  See malloc_hook.h for details
 * on how to use these.
 */

#ifndef _MALLOC_HOOK_C_H_
#define _MALLOC_HOOK_C_H_

#include 
#include 

/* Annoying stuff for windows; makes sure clients can import these functions */
#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

/* Get the current stack trace.  Try to skip all routines up to and
 * and including the caller of MallocHook::Invoke*.
 * Use "skip_count" (similarly to GetStackTrace from stacktrace.h)
 * as a hint about how many routines to skip if better information
 * is not available.
 */
PERFTOOLS_DLL_DECL
int MallocHook_GetCallerStackTrace(void** result, int max_depth,
                                   int skip_count);

/* The MallocHook_{Add,Remove}*Hook functions return 1 on success and 0 on
 * failure.
 */

typedef void (*MallocHook_NewHook)(const void* ptr, size_t size);
PERFTOOLS_DLL_DECL
int MallocHook_AddNewHook(MallocHook_NewHook hook);
PERFTOOLS_DLL_DECL
int MallocHook_RemoveNewHook(MallocHook_NewHook hook);

typedef void (*MallocHook_DeleteHook)(const void* ptr);
PERFTOOLS_DLL_DECL
int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook);
PERFTOOLS_DLL_DECL
int MallocHook_RemoveDeleteHook(MallocHook_DeleteHook hook);

typedef void (*MallocHook_PreMmapHook)(const void *start,
                                       size_t size,
                                       int protection,
                                       int flags,
                                       int fd,
                                       off_t offset);
PERFTOOLS_DLL_DECL
int MallocHook_AddPreMmapHook(MallocHook_PreMmapHook hook);
PERFTOOLS_DLL_DECL
int MallocHook_RemovePreMmapHook(MallocHook_PreMmapHook hook);

typedef void (*MallocHook_MmapHook)(const void* result,
                                    const void* start,
                                    size_t size,
                                    int protection,
                                    int flags,
                                    int fd,
                                    off_t offset);
PERFTOOLS_DLL_DECL
int MallocHook_AddMmapHook(MallocHook_MmapHook hook);
PERFTOOLS_DLL_DECL
int MallocHook_RemoveMmapHook(MallocHook_MmapHook hook);

typedef int (*MallocHook_MmapReplacement)(const void* start,
                                          size_t size,
                                          int protection,
                                          int flags,
                                          int fd,
                                          off_t offset,
                                          void** result);
int MallocHook_SetMmapReplacement(MallocHook_MmapReplacement hook);
int MallocHook_RemoveMmapReplacement(MallocHook_MmapReplacement hook);

typedef void (*MallocHook_MunmapHook)(const void* ptr, size_t size);
PERFTOOLS_DLL_DECL
int MallocHook_AddMunmapHook(MallocHook_MunmapHook hook);
PERFTOOLS_DLL_DECL
int MallocHook_RemoveMunmapHook(MallocHook_MunmapHook hook);

typedef int (*MallocHook_MunmapReplacement)(const void* ptr,
                                            size_t size,
                                            int* result);
int MallocHook_SetMunmapReplacement(MallocHook_MunmapReplacement hook);
int MallocHook_RemoveMunmapReplacement(MallocHook_MunmapReplacement hook);

typedef void (*MallocHook_MremapHook)(const void* result,
                                      const void* old_addr,
                                      size_t old_size,
                                      size_t new_size,
                                      int flags,
                                      const void* new_addr);
PERFTOOLS_DLL_DECL
int MallocHook_AddMremapHook(MallocHook_MremapHook hook);
PERFTOOLS_DLL_DECL
int MallocHook_RemoveMremapHook(MallocHook_MremapHook hook);

typedef void (*MallocHook_PreSbrkHook)(ptrdiff_t increment);
PERFTOOLS_DLL_DECL
int MallocHook_AddPreSbrkHook(MallocHook_PreSbrkHook hook);
PERFTOOLS_DLL_DECL
int MallocHook_RemovePreSbrkHook(MallocHook_PreSbrkHook hook);

typedef void (*MallocHook_SbrkHook)(const void* result, ptrdiff_t increment);
PERFTOOLS_DLL_DECL
int MallocHook_AddSbrkHook(MallocHook_SbrkHook hook);
PERFTOOLS_DLL_DECL
int MallocHook_RemoveSbrkHook(MallocHook_SbrkHook hook);

/* The following are DEPRECATED. */
PERFTOOLS_DLL_DECL
MallocHook_NewHook MallocHook_SetNewHook(MallocHook_NewHook hook);
PERFTOOLS_DLL_DECL
MallocHook_DeleteHook MallocHook_SetDeleteHook(MallocHook_DeleteHook hook);
PERFTOOLS_DLL_DECL
MallocHook_PreMmapHook MallocHook_SetPreMmapHook(MallocHook_PreMmapHook hook);
PERFTOOLS_DLL_DECL
MallocHook_MmapHook MallocHook_SetMmapHook(MallocHook_MmapHook hook);
PERFTOOLS_DLL_DECL
MallocHook_MunmapHook MallocHook_SetMunmapHook(MallocHook_MunmapHook hook);
PERFTOOLS_DLL_DECL
MallocHook_MremapHook MallocHook_SetMremapHook(MallocHook_MremapHook hook);
PERFTOOLS_DLL_DECL
MallocHook_PreSbrkHook MallocHook_SetPreSbrkHook(MallocHook_PreSbrkHook hook);
PERFTOOLS_DLL_DECL
MallocHook_SbrkHook MallocHook_SetSbrkHook(MallocHook_SbrkHook hook);
/* End of DEPRECATED functions. */

#ifdef __cplusplus
}   // extern "C"
#endif

#endif /* _MALLOC_HOOK_C_H_ */
gperftools-gperftools-2.18/src/gperftools/nallocx.h000066400000000000000000000016501513545575200226140ustar00rootroot00000000000000#ifndef _NALLOCX_H_
#define _NALLOCX_H_
#include 

#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#  define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#  define PERFTOOLS_DLL_DECL
# endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define MALLOCX_LG_ALIGN(la) ((int)(la))

/*
 * The nallocx function allocates no memory, but it performs the same size
 * computation as the malloc function, and returns the real size of the
 * allocation that would result from the equivalent malloc function call.
 * nallocx is a malloc extension originally implemented by jemalloc:
 * http://www.unix.com/man-page/freebsd/3/nallocx/
 *
 * Note, we only support MALLOCX_LG_ALIGN flag and nothing else.
 */
PERFTOOLS_DLL_DECL size_t nallocx(size_t size, int flags);

/* same as above but never weak */
PERFTOOLS_DLL_DECL size_t tc_nallocx(size_t size, int flags);

#ifdef __cplusplus
}   /* extern "C" */
#endif

#endif /* _NALLOCX_H_ */
gperftools-gperftools-2.18/src/gperftools/profiler.h000066400000000000000000000145101513545575200227750ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* Copyright (c) 2005, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Sanjay Ghemawat
 *
 * Module for CPU profiling based on periodic pc-sampling.
 *
 * For full(er) information, see docs/cpuprofile.html
 *
 * This module is linked into your program with
 * no slowdown caused by this unless you activate the profiler
 * using one of the following methods:
 *
 *    1. Before starting the program, set the environment variable
 *       "CPUPROFILE" to be the name of the file to which the profile
 *       data should be written.
 *
 *    2. Programmatically, start and stop the profiler using the
 *       routines "ProfilerStart(filename)" and "ProfilerStop()".
 *
 *
 * (Note: if using linux 2.4 or earlier, only the main thread may be
 * profiled.)
 *
 * Use pprof to view the resulting profile output.
 *    % pprof  
 *    % pprof --gv   
 *
 * These functions are thread-safe.
 */

#ifndef BASE_PROFILER_H_
#define BASE_PROFILER_H_

#include        /* For time_t */

/* Annoying stuff for windows; makes sure clients can import these functions */
#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif

/* All this code should be usable from within C apps. */
#ifdef __cplusplus
extern "C" {
#endif

/* Profiler options, for use with ProfilerStartWithOptions.  To use:
 *
 *   struct ProfilerOptions options;
 *   memset(&options, 0, sizeof options);
 *
 * then fill in fields as needed.
 *
 * This structure is intended to be usable from C code, so no constructor
 * is provided to initialize it.  (Use memset as described above).
 */
struct ProfilerOptions {
  /* Filter function and argument.
   *
   * If filter_in_thread is not nullptr, when a profiling tick is delivered
   * the profiler will call:
   *
   *   (*filter_in_thread)(filter_in_thread_arg)
   *
   * If it returns nonzero, the sample will be included in the profile.
   * Note that filter_in_thread runs in a signal handler, so must be
   * async-signal-safe.
   *
   * A typical use would be to set up filter results for each thread
   * in the system before starting the profiler, then to make
   * filter_in_thread be a very simple function which retrieves those
   * results in an async-signal-safe way.  Retrieval could be done
   * using thread-specific data, or using a shared data structure that
   * supports async-signal-safe lookups.
   */
  int (*filter_in_thread)(void *arg);
  void *filter_in_thread_arg;
};

/* Start profiling and write profile info into fname, discarding any
 * existing profiling data in that file.
 *
 * This is equivalent to calling ProfilerStartWithOptions(fname, nullptr).
 */
PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname);

/* Start profiling and write profile into fname, discarding any
 * existing profiling data in that file.
 *
 * The profiler is configured using the options given by 'options'.
 * Options which are not specified are given default values.
 *
 * 'options' may be nullptr, in which case all are given default values.
 *
 * Returns nonzero if profiling was started successfully, or zero else.
 */
PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
    const char *fname, const struct ProfilerOptions *options);

/* Stop profiling. Can be started again with ProfilerStart(), but
 * the currently accumulated profiling data will be cleared.
 */
PERFTOOLS_DLL_DECL void ProfilerStop(void);

/* Flush any currently buffered profiling state to the profile file.
 * Has no effect if the profiler has not been started.
 */
PERFTOOLS_DLL_DECL void ProfilerFlush(void);


/* DEPRECATED: these functions were used to enable/disable profiling
 * in the current thread, but no longer do anything.
 */
PERFTOOLS_DLL_DECL void ProfilerEnable(void);
PERFTOOLS_DLL_DECL void ProfilerDisable(void);

/* Returns nonzero if profile is currently enabled, zero if it's not. */
PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads(void);

/* Routine for registering new threads with the profiler.
 */
PERFTOOLS_DLL_DECL void ProfilerRegisterThread(void);

/* Stores state about profiler's current status into "*state". */
struct ProfilerState {
  int    enabled;             /* Is profiling currently enabled? */
  time_t start_time;          /* If enabled, when was profiling started? */
  char   profile_name[1024];  /* Name of profile file being written, or '\0' */
  int    samples_gathered;    /* Number of samples gathered so far (or 0) */
};
PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(struct ProfilerState* state);

/* Returns the current stack trace, to be called from a SIGPROF handler. */
PERFTOOLS_DLL_DECL int ProfilerGetStackTrace(
    void** result, int max_depth, int skip_count, const void *uc);

#ifdef __cplusplus
}  // extern "C"
#endif

#endif  /* BASE_PROFILER_H_ */
gperftools-gperftools-2.18/src/gperftools/stacktrace.h000066400000000000000000000115441513545575200233030ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// Routines to extract the current stack trace.  These functions are
// thread-safe.

#ifndef GOOGLE_STACKTRACE_H_
#define GOOGLE_STACKTRACE_H_

// Annoying stuff for windows -- makes sure clients can import these functions
#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif


// Skips the most recent "skip_count" stack frames (also skips the
// frame generated for the "GetStackFrames" routine itself), and then
// records the pc values for up to the next "max_depth" frames in
// "result", and the corresponding stack frame sizes in "sizes".
// Returns the number of values recorded in "result"/"sizes".
//
// Example:
//      main() { foo(); }
//      foo() { bar(); }
//      bar() {
//        void* result[10];
//        int sizes[10];
//        int depth = GetStackFrames(result, sizes, 10, 1);
//      }
//
// The GetStackFrames call will skip the frame for "bar".  It will
// return 2 and will produce pc values that map to the following
// procedures:
//      result[0]       foo
//      result[1]       main
// (Actually, there may be a few more entries after "main" to account for
// startup procedures.)
// And corresponding stack frame sizes will also be recorded:
//    sizes[0]       16
//    sizes[1]       16
// (Stack frame sizes of 16 above are just for illustration purposes.)
// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
// be identified.
//
// This routine may return fewer stack frame entries than are
// available. Also note that "result" and "sizes" must both be non-nullptr.
extern PERFTOOLS_DLL_DECL int GetStackFrames(void** result, int* sizes, int max_depth,
                          int skip_count);

// Same as above, but to be used from a signal handler. The "uc" parameter
// should be the pointer to ucontext_t which was passed as the 3rd parameter
// to sa_sigaction signal handler. It may help the unwinder to get a
// better stack trace under certain conditions. The "uc" may safely be nullptr.
extern PERFTOOLS_DLL_DECL int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
                                     int skip_count, const void *uc);

// This is similar to the GetStackFrames routine, except that it returns
// the stack trace only, and not the stack frame sizes as well.
// Example:
//      main() { foo(); }
//      foo() { bar(); }
//      bar() {
//        void* result[10];
//        int depth = GetStackTrace(result, 10, 1);
//      }
//
// This produces:
//      result[0]       foo
//      result[1]       main
//           ....       ...
//
// "result" must not be nullptr.
extern PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth,
                                            int skip_count);

// Same as above, but to be used from a signal handler. The "uc" parameter
// should be the pointer to ucontext_t which was passed as the 3rd parameter
// to sa_sigaction signal handler. It may help the unwinder to get a
// better stack trace under certain conditions. The "uc" may safely be nullptr.
extern PERFTOOLS_DLL_DECL int GetStackTraceWithContext(void** result, int max_depth,
                                    int skip_count, const void *uc);

#endif /* GOOGLE_STACKTRACE_H_ */
gperftools-gperftools-2.18/src/gperftools/tcmalloc.h000066400000000000000000000201771513545575200227570ustar00rootroot00000000000000/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* Copyright (c) 2003, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Sanjay Ghemawat 
 *         .h file by Craig Silverstein 
 */

#ifndef TCMALLOC_TCMALLOC_H_
#define TCMALLOC_TCMALLOC_H_

#include                      /* for size_t */
#ifdef __cplusplus
#include                           /* for std::nothrow_t, std::align_val_t */
#endif

/* Define the version number so folks can check against it */
/* Note, maintainers are expected to update this to match configure.ac for each release */
#define TC_VERSION_MAJOR  2
#define TC_VERSION_MINOR  18
#define TC_VERSION_PATCH  ""
#define TC_VERSION_STRING "gperftools 2.18"

#if __GLIBC__ * 1000 + __GLIBC_MINOR__ >= 2033
/* glibc 2.33 has mallinfo2 */
#define GPERFTOOLS_HAS_MALLINFO2 1
#define GPERFTOOLS_HAS_MALLINFO 1
#elif defined(__GLIBC__)
/* earlier glibc-s have mallinfo */
#define GPERFTOOLS_HAS_MALLINFO 1
#elif defined(__sun__)
/* Some version of Solaris actually introduced mallinfo. It is still
 * there with current opensolaris. */
#define GPERFTOOLS_HAS_MALLINFO 1
#elif defined(__ANDROID__) && __ANDROID_API__ >= 34
/* ndk 24 has mallinfo2 */
#define GPERFTOOLS_HAS_MALLINFO2 1
#define GPERFTOOLS_HAS_MALLINFO 1
#elif defined(__ANDROID__)
#define GPERFTOOLS_HAS_MALLINFO 1
#endif
// musl doesn't do mallinfo
// uclibc does in a subset of configs, but given mallinfo is rare API we keep it simple.

/* For struct mallinfo, if it's defined. */
#if GPERFTOOLS_HAS_MALLINFO || GPERFTOOLS_HAS_MALLINFO2
# include 
#endif

#ifndef PERFTOOLS_NOTHROW

#ifdef __cplusplus
#define PERFTOOLS_NOTHROW noexcept
#else
# ifdef __GNUC__
#  define PERFTOOLS_NOTHROW __attribute__((__nothrow__))
# else
#  define PERFTOOLS_NOTHROW
# endif
#endif

#endif

#ifndef PERFTOOLS_DLL_DECL
# ifdef _WIN32
#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
# else
#   define PERFTOOLS_DLL_DECL
# endif
#endif

#ifdef __cplusplus
extern "C" {
#endif
  /*
   * Returns a human-readable version string.  If major, minor,
   * and/or patch are not nullptr, they are set to the major version,
   * minor version, and patch-code (a string, usually "").
   */
  PERFTOOLS_DLL_DECL const char* tc_version(int* major, int* minor,
                                            const char** patch) PERFTOOLS_NOTHROW;

  PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void* tc_malloc_skip_new_handler(size_t size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_free(void* ptr) PERFTOOLS_NOTHROW;

  // Versions of C23 sized free stuff
  PERFTOOLS_DLL_DECL void tc_free_sized(void *ptr, size_t size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_free_aligned_sized(void* ptr, size_t align, size_t size) PERFTOOLS_NOTHROW;

  PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) PERFTOOLS_NOTHROW;

  PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment,
                                       size_t __size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr,
                                           size_t align, size_t size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) PERFTOOLS_NOTHROW;

  PERFTOOLS_DLL_DECL void tc_malloc_stats(void) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) PERFTOOLS_NOTHROW;


#if GPERFTOOLS_HAS_MALLINFO
  PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) PERFTOOLS_NOTHROW;
#endif
#if GPERFTOOLS_HAS_MALLINFO2
  PERFTOOLS_DLL_DECL struct mallinfo2 tc_mallinfo2(void) PERFTOOLS_NOTHROW;
#endif

  /*
   * This is an alias for MallocExtension::instance()->GetAllocatedSize().
   * It is equivalent to
   *    OS X: malloc_size()
   *    glibc: malloc_usable_size()
   *    Windows: _msize()
   */
  PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) PERFTOOLS_NOTHROW;

#ifdef __cplusplus
  PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void* tc_new(size_t size);
  PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size,
                                          const std::nothrow_t&) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_delete(void* p) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_delete_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p,
                                            const std::nothrow_t&) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void* tc_newarray(size_t size);
  PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size,
                                               const std::nothrow_t&) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_deletearray(void* p) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_deletearray_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p,
                                                 const std::nothrow_t&) PERFTOOLS_NOTHROW;

#if defined(__cpp_aligned_new) || \
    (defined(__cplusplus) && __cplusplus >= 201703L) || \
    (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
  PERFTOOLS_DLL_DECL void* tc_new_aligned(size_t size, std::align_val_t al);
  PERFTOOLS_DLL_DECL void* tc_new_aligned_nothrow(size_t size, std::align_val_t al,
                                          const std::nothrow_t&) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_delete_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_delete_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_delete_aligned_nothrow(void* p, std::align_val_t al,
                                            const std::nothrow_t&) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void* tc_newarray_aligned(size_t size, std::align_val_t al);
  PERFTOOLS_DLL_DECL void* tc_newarray_aligned_nothrow(size_t size, std::align_val_t al,
                                               const std::nothrow_t&) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_deletearray_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_deletearray_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
  PERFTOOLS_DLL_DECL void tc_deletearray_aligned_nothrow(void* p, std::align_val_t al,
                                                 const std::nothrow_t&) PERFTOOLS_NOTHROW;
#endif

}
#endif

/* We're only un-defining for public */
#if !defined(GPERFTOOLS_CONFIG_H_)

#undef PERFTOOLS_NOTHROW

#endif /* GPERFTOOLS_CONFIG_H_ */

#endif  /* #ifndef TCMALLOC_TCMALLOC_H_ */
gperftools-gperftools-2.18/src/heap-checker-stub.cc000066400000000000000000000046711513545575200224260ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config.h"

#include "gperftools/heap-checker.h"

bool HeapLeakChecker::IsActive() { return false; }
HeapLeakChecker* HeapLeakChecker::GlobalChecker() { return nullptr; }
bool HeapLeakChecker::NoGlobalLeaks() { return true; }
void HeapLeakChecker::CancelGlobalCheck() {}
HeapLeakChecker::HeapLeakChecker(const char* name) {}
HeapLeakChecker::~HeapLeakChecker() = default;
ptrdiff_t HeapLeakChecker::BytesLeaked() const { return 0; }
ptrdiff_t HeapLeakChecker::ObjectsLeaked() const { return 0; }
void HeapLeakChecker::UnIgnoreObject(const void* ptr) {}
bool HeapLeakChecker::DoNoLeaks(HeapLeakChecker::ShouldSymbolize should_symbolize) { return true; }
void HeapLeakChecker::DoIgnoreObject(const void* ptr) {}
void HeapCleaner::RunHeapCleanups() {}

HeapLeakChecker::Disabler::Disabler() {}
HeapLeakChecker::Disabler::~Disabler() = default;
gperftools-gperftools-2.18/src/heap-profile-stats.h000066400000000000000000000067721513545575200225110ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2013, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// This file defines structs to accumulate memory allocation and
// deallocation counts.  These structs are commonly used for malloc
// profiles (in HeapProfileTable).

// A bucket is data structure for heap profiling to store a pair of a stack
// trace and counts of (de)allocation.  Buckets are stored in a hash table
// which is declared as "HeapProfileBucket**".
//
// A hash value is computed from a stack trace.  Collision in the hash table
// is resolved by separate chaining with linked lists.  The links in the list
// are implemented with the member "HeapProfileBucket* next".
//
// A structure of a hash table HeapProfileBucket** bucket_table would be like:
// bucket_table[0] => nullptr
// bucket_table[1] => HeapProfileBucket() => HeapProfileBucket() => nullptr
// ...
// bucket_table[i] => HeapProfileBucket() => nullptr
// ...
// bucket_table[n] => HeapProfileBucket() => nullptr

#ifndef HEAP_PROFILE_STATS_H_
#define HEAP_PROFILE_STATS_H_

#include 

struct HeapProfileStats {
  // Returns true if the two HeapProfileStats are semantically equal.
  bool Equivalent(const HeapProfileStats& other) const {
    return allocs - frees == other.allocs - other.frees &&
        alloc_size - free_size == other.alloc_size - other.free_size;
  }

  int64_t allocs;      // Number of allocation calls.
  int64_t frees;       // Number of free calls.
  int64_t alloc_size;  // Total size of all allocated objects so far.
  int64_t free_size;   // Total size of all freed objects so far.
};

// Allocation and deallocation statistics per each stack trace.
struct HeapProfileBucket : public HeapProfileStats {
  // Longest stack trace we record.
  static const int kMaxStackDepth = 32;

  uintptr_t hash;           // Hash value of the stack trace.
  int depth;                // Depth of stack trace.
  const void** stack;       // Stack trace.
  HeapProfileBucket* next;  // Next entry in hash-table.
};

#endif  // HEAP_PROFILE_STATS_H_
gperftools-gperftools-2.18/src/heap-profile-table.cc000066400000000000000000000244041513545575200225700ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//         Maxim Lifantsev (refactoring)
//

#include 

#ifdef HAVE_UNISTD_H
#include    // for write()
#endif
#include     // for open()
#ifdef HAVE_GLOB_H
#include 
#ifndef GLOB_NOMATCH  // true on some old cygwins
# define GLOB_NOMATCH 0
#endif
#endif
#include  // for PRIxPTR
#ifdef HAVE_POLL_H
#include 
#endif
#include 

#include   // for sort(), equal(), and copy()
#include 

#include "heap-profile-table.h"

#include "base/commandlineflags.h"
#include "base/logging.h"
#include "base/proc_maps_iterator.h"

//----------------------------------------------------------------------

DEFINE_bool(cleanup_old_heap_profiles,
            EnvToBool("HEAP_PROFILE_CLEANUP", true),
            "At initialization time, delete old heap profiles.");

DEFINE_int32(heap_check_max_leaks,
             EnvToInt("HEAP_CHECK_MAX_LEAKS", 20),
             "The maximum number of leak reports to print.");

//----------------------------------------------------------------------

// header of the dumped heap profile
static const char kProfileHeader[] = "heap profile: ";
static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n";

//----------------------------------------------------------------------

const char HeapProfileTable::kFileExt[] = ".heap";

//----------------------------------------------------------------------

static constexpr int kHashTableSize = 179999;   // Size for bucket_table_.

//----------------------------------------------------------------------

HeapProfileTable::HeapProfileTable(Allocator alloc,
                                   DeAllocator dealloc)
    : alloc_(alloc),
      dealloc_(dealloc),
      bucket_table_(nullptr),
      num_buckets_(0),
      address_map_(nullptr) {
  // Make a hash table for buckets.
  const int table_bytes = kHashTableSize * sizeof(*bucket_table_);
  bucket_table_ = static_cast(alloc_(table_bytes));
  memset(bucket_table_, 0, table_bytes);

  // Make an allocation map.
  address_map_ =
      new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_);

  // Initialize.
  memset(&total_, 0, sizeof(total_));
  num_buckets_ = 0;
}

HeapProfileTable::~HeapProfileTable() {
  // Free the allocation map.
  address_map_->~AllocationMap();
  dealloc_(address_map_);
  address_map_ = nullptr;

  // Free the hash table.
  for (int i = 0; i < kHashTableSize; i++) {
    for (Bucket* curr = bucket_table_[i]; curr != 0; /**/) {
      Bucket* bucket = curr;
      curr = curr->next;
      dealloc_(bucket->stack);
      dealloc_(bucket);
    }
  }
  dealloc_(bucket_table_);
  bucket_table_ = nullptr;
}

HeapProfileTable::Bucket* HeapProfileTable::GetBucket(int depth,
                                                      const void* const key[]) {
  // Make hash-value
  uintptr_t h = 0;
  for (int i = 0; i < depth; i++) {
    h += reinterpret_cast(key[i]);
    h += h << 10;
    h ^= h >> 6;
  }
  h += h << 3;
  h ^= h >> 11;

  // Lookup stack trace in table
  unsigned int buck = ((unsigned int) h) % kHashTableSize;
  for (Bucket* b = bucket_table_[buck]; b != 0; b = b->next) {
    if ((b->hash == h) &&
        (b->depth == depth) &&
        std::equal(key, key + depth, b->stack)) {
      return b;
    }
  }

  // Create new bucket
  const size_t key_size = sizeof(key[0]) * depth;
  const void** kcopy = reinterpret_cast(alloc_(key_size));
  std::copy(key, key + depth, kcopy);
  Bucket* b = reinterpret_cast(alloc_(sizeof(Bucket)));
  memset(b, 0, sizeof(*b));
  b->hash  = h;
  b->depth = depth;
  b->stack = kcopy;
  b->next  = bucket_table_[buck];
  bucket_table_[buck] = b;
  num_buckets_++;
  return b;
}

void HeapProfileTable::RecordAlloc(
    const void* ptr, size_t bytes, int stack_depth,
    const void* const call_stack[]) {
  Bucket* b = GetBucket(stack_depth, call_stack);
  b->allocs++;
  b->alloc_size += bytes;
  total_.allocs++;
  total_.alloc_size += bytes;

  AllocValue v;
  v.set_bucket(b);  // also did set_live(false); set_ignore(false)
  v.bytes = bytes;
  address_map_->Insert(ptr, v);
}

void HeapProfileTable::RecordFree(const void* ptr) {
  AllocValue v;
  if (address_map_->FindAndRemove(ptr, &v)) {
    Bucket* b = v.bucket();
    b->frees++;
    b->free_size += v.bytes;
    total_.frees++;
    total_.free_size += v.bytes;
  }
}

bool HeapProfileTable::FindAlloc(const void* ptr, size_t* object_size) const {
  const AllocValue* alloc_value = address_map_->Find(ptr);
  if (alloc_value != nullptr) *object_size = alloc_value->bytes;
  return alloc_value != nullptr;
}

bool HeapProfileTable::FindAllocDetails(const void* ptr,
                                        AllocInfo* info) const {
  const AllocValue* alloc_value = address_map_->Find(ptr);
  if (alloc_value != nullptr) {
    info->object_size = alloc_value->bytes;
    info->call_stack = alloc_value->bucket()->stack;
    info->stack_depth = alloc_value->bucket()->depth;
  }
  return alloc_value != nullptr;
}

bool HeapProfileTable::FindInsideAlloc(const void* ptr,
                                       size_t max_size,
                                       const void** object_ptr,
                                       size_t* object_size) const {
  const AllocValue* alloc_value =
    address_map_->FindInside(&AllocValueSize, max_size, ptr, object_ptr);
  if (alloc_value != nullptr) *object_size = alloc_value->bytes;
  return alloc_value != nullptr;
}

bool HeapProfileTable::MarkAsLive(const void* ptr) {
  AllocValue* alloc = address_map_->FindMutable(ptr);
  if (alloc && !alloc->live()) {
    alloc->set_live(true);
    return true;
  }
  return false;
}

void HeapProfileTable::MarkAsIgnored(const void* ptr) {
  AllocValue* alloc = address_map_->FindMutable(ptr);
  if (alloc) {
    alloc->set_ignore(true);
  }
}

void HeapProfileTable::UnparseBucket(const Bucket& b,
                                     tcmalloc::GenericWriter* writer,
                                     const char* extra) {
  writer->AppendF("%6" PRId64 ": %8" PRId64 " [%6" PRId64 ": %8" PRId64 "] @",
                  b.allocs - b.frees,
                  b.alloc_size - b.free_size,
                  b.allocs,
                  b.alloc_size);
  writer->AppendStr(extra);

  for (int d = 0; d < b.depth; d++) {
    writer->AppendF(" 0x%08" PRIxPTR,
                    reinterpret_cast(b.stack[d]));
  }
  writer->AppendStr("\n");
}

void HeapProfileTable::SaveProfile(tcmalloc::GenericWriter* writer) const {
  writer->AppendStr(kProfileHeader);
  UnparseBucket(total_, writer, " heapprofile");

  int bucket_count = 0;
  for (int i = 0; i < kHashTableSize; i++) {
    for (Bucket* curr = bucket_table_[i]; curr != nullptr; curr = curr->next) {
      UnparseBucket(*curr, writer, "");
      bucket_count++;
    }
  }
  RAW_DCHECK(bucket_count == num_buckets_, "");
  (void)bucket_count;

  writer->AppendStr(kProcSelfMapsHeader);
  tcmalloc::SaveProcSelfMaps(writer);
}

bool HeapProfileTable::WriteProfile(const char* file_name,
                                    const Bucket& total,
                                    AllocationMap* allocations) {
  RAW_VLOG(1, "Dumping non-live heap profile to %s", file_name);
  RawFD fd = RawOpenForWriting(file_name);
  if (fd == kIllegalRawFD) {
    RAW_LOG(ERROR, "Failed dumping filtered heap profile to %s", file_name);
    return false;
  }

  tcmalloc::RawFDGenericWriter<> writer{fd};

  writer.AppendStr(kProfileHeader);

  UnparseBucket(total, &writer, " heapprofile");

  allocations->Iterate([&writer] (const void* ptr, AllocValue* v) {
    if (v->live()) {
      v->set_live(false);
      return;
    }
    if (v->ignore()) {
      return;
    }
    Bucket b;
    memset(&b, 0, sizeof(b));
    b.allocs = 1;
    b.alloc_size = v->bytes;
    b.depth = v->bucket()->depth;
    b.stack = v->bucket()->stack;
    UnparseBucket(b, &writer, "");
  });

  RawWrite(fd, kProcSelfMapsHeader, strlen(kProcSelfMapsHeader));
  tcmalloc::SaveProcSelfMapsToRawFD(fd);

  RawClose(fd);
  return true;
}

void HeapProfileTable::CleanupOldProfiles(const char* prefix) {
  if (!FLAGS_cleanup_old_heap_profiles)
    return;
  std::string pattern = std::string(prefix) + ".*" + kFileExt;
#if defined(HAVE_GLOB_H)
  glob_t g;
  const int r = glob(pattern.c_str(), GLOB_ERR, nullptr, &g);
  if (r == 0 || r == GLOB_NOMATCH) {
    const int prefix_length = strlen(prefix);
    for (int i = 0; i < g.gl_pathc; i++) {
      const char* fname = g.gl_pathv[i];
      if ((strlen(fname) >= prefix_length) &&
          (memcmp(fname, prefix, prefix_length) == 0)) {
        RAW_VLOG(1, "Removing old heap profile %s", fname);
        unlink(fname);
      }
    }
  }
  globfree(&g);
#else   /* HAVE_GLOB_H */
  RAW_LOG(WARNING, "Unable to remove old heap profiles (can't run glob())");
#endif
}
gperftools-gperftools-2.18/src/heap-profile-table.h000066400000000000000000000205751513545575200224370ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//         Maxim Lifantsev (refactoring)
//

#ifndef BASE_HEAP_PROFILE_TABLE_H_
#define BASE_HEAP_PROFILE_TABLE_H_

#include "addressmap-inl.h"
#include "base/basictypes.h"
#include "base/generic_writer.h"
#include "heap-profile-stats.h"

// Table to maintain a heap profile data inside,
// i.e. the set of currently active heap memory allocations.
// thread-unsafe and non-reentrant code:
// each instance object must be used by one thread
// at a time w/o self-recursion.
//
// TODO(maxim): add a unittest for this class.
class HeapProfileTable {
 public:

  // Extension to be used for heap pforile files.
  static const char kFileExt[];

  // data types ----------------------------

  // Profile stats.
  typedef HeapProfileStats Stats;

  // Info we can return about an allocation.
  struct AllocInfo {
    size_t object_size;  // size of the allocation
    const void* const* call_stack;  // call stack that made the allocation call
    int stack_depth;  // depth of call_stack
    bool live;
    bool ignored;
  };

  // Memory (de)allocator interface we'll use.
  typedef void* (*Allocator)(size_t size);
  typedef void  (*DeAllocator)(void* ptr);

  // interface ---------------------------

  HeapProfileTable(Allocator alloc, DeAllocator dealloc);
  ~HeapProfileTable();

  // Record an allocation at 'ptr' of 'bytes' bytes.  'stack_depth'
  // and 'call_stack' identifying the function that requested the
  // allocation. They can be generated using GetCallerStackTrace() above.
  void RecordAlloc(const void* ptr, size_t bytes,
                   int stack_depth, const void* const call_stack[]);

  // Record the deallocation of memory at 'ptr'.
  void RecordFree(const void* ptr);

  // Return true iff we have recorded an allocation at 'ptr'.
  // If yes, fill *object_size with the allocation byte size.
  bool FindAlloc(const void* ptr, size_t* object_size) const;
  // Same as FindAlloc, but fills all of *info.
  bool FindAllocDetails(const void* ptr, AllocInfo* info) const;

  // Return true iff "ptr" points into a recorded allocation
  // If yes, fill *object_ptr with the actual allocation address
  // and *object_size with the allocation byte size.
  // max_size specifies largest currently possible allocation size.
  bool FindInsideAlloc(const void* ptr, size_t max_size,
                       const void** object_ptr, size_t* object_size) const;

  // If "ptr" points to a recorded allocation and it's not marked as live
  // mark it as live and return true. Else return false.
  // All allocations start as non-live.
  bool MarkAsLive(const void* ptr);

  // If "ptr" points to a recorded allocation, mark it as "ignored".
  // Ignored objects are treated like other objects, except that they
  // are skipped in heap checking reports.
  void MarkAsIgnored(const void* ptr);

  // Return current total (de)allocation statistics.  It doesn't contain
  // mmap'ed regions.
  const Stats& total() const { return total_; }

  // Allocation data iteration callback: gets passed object pointer and
  // fully-filled AllocInfo.
  typedef void (*AllocIterator)(const void* ptr, const AllocInfo& info);

  // Iterate over the allocation profile data calling "callback"
  // for every allocation.
  void IterateAllocs(AllocIterator callback) const {
    address_map_->Iterate([callback] (const void* ptr, AllocValue* v) {
      AllocInfo info;
      info.object_size = v->bytes;
      info.call_stack = v->bucket()->stack;
      info.stack_depth = v->bucket()->depth;
      info.live = v->live();
      info.ignored = v->ignore();
      callback(ptr, info);
    });
  }

  void SaveProfile(tcmalloc::GenericWriter* write) const;

  // Cleanup any old profile files matching prefix + ".*" + kFileExt.
  static void CleanupOldProfiles(const char* prefix);

 private:
  // data types ----------------------------

  // Hash table bucket to hold (de)allocation stats
  // for a given allocation call stack trace.
  typedef HeapProfileBucket Bucket;

  // Info stored in the address map
  struct AllocValue {
    // Access to the stack-trace bucket
    Bucket* bucket() const {
      return reinterpret_cast(bucket_rep & ~uintptr_t(kMask));
    }
    // This also does set_live(false).
    void set_bucket(Bucket* b) { bucket_rep = reinterpret_cast(b); }
    size_t  bytes;   // Number of bytes in this allocation

    // Access to the allocation liveness flag (for leak checking)
    bool live() const { return bucket_rep & kLive; }
    void set_live(bool l) {
      bucket_rep = (bucket_rep & ~uintptr_t(kLive)) | (l ? kLive : 0);
    }

    // Should this allocation be ignored if it looks like a leak?
    bool ignore() const { return bucket_rep & kIgnore; }
    void set_ignore(bool r) {
      bucket_rep = (bucket_rep & ~uintptr_t(kIgnore)) | (r ? kIgnore : 0);
    }

   private:
    // We store a few bits in the bottom bits of bucket_rep.
    // (Alignment is at least four, so we have at least two bits.)
    static const int kLive = 1;
    static const int kIgnore = 2;
    static const int kMask = kLive | kIgnore;

    uintptr_t bucket_rep;
  };

  // helper for FindInsideAlloc
  static size_t AllocValueSize(const AllocValue& v) { return v.bytes; }

  typedef AddressMap AllocationMap;

  // helpers ----------------------------

  // Unparse bucket b and print its portion of profile dump into given
  // writer.
  //
  // "extra" is appended to the unparsed bucket.  Typically it is empty,
  // but may be set to something like " heapprofile" for the total
  // bucket to indicate the type of the profile.
  static void UnparseBucket(const Bucket& b,
                            tcmalloc::GenericWriter* writer,
                            const char* extra);

  // Get the bucket for the caller stack trace 'key' of depth 'depth'
  // creating the bucket if needed.
  Bucket* GetBucket(int depth, const void* const key[]);

  // Write contents of "*allocations" as a heap profile to
  // "file_name".  "total" must contain the total of all entries in
  // "*allocations".
  static bool WriteProfile(const char* file_name,
                           const Bucket& total,
                           AllocationMap* allocations);

  // data ----------------------------

  // Memory (de)allocator that we use.
  Allocator alloc_;
  DeAllocator dealloc_;

  // Overall profile stats; we use only the Stats part,
  // but make it a Bucket to pass to UnparseBucket.
  Bucket total_;

  // Bucket hash table for malloc.
  // We hand-craft one instead of using one of the pre-written
  // ones because we do not want to use malloc when operating on the table.
  // It is only few lines of code, so no big deal.
  Bucket** bucket_table_;
  int num_buckets_;

  // Map of all currently allocated objects and mapped regions we know about.
  AllocationMap* address_map_;

  DISALLOW_COPY_AND_ASSIGN(HeapProfileTable);
};

#endif  // BASE_HEAP_PROFILE_TABLE_H_
gperftools-gperftools-2.18/src/heap-profiler.cc000066400000000000000000000401551513545575200216660ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// TODO: Log large allocations

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifdef HAVE_FCNTL_H
#include     // for open()
#endif
#ifdef HAVE_UNISTD_H
#include 
#endif

#include 

#include "base/logging.h"
#include "base/googleinit.h"
#include "base/commandlineflags.h"
#include "tcmalloc_guard.h"
#include 
#include 
#include "base/spinlock.h"
#include "base/low_level_alloc.h"
#include "base/sysinfo.h"      // for GetUniquePathFromEnv()
#include "heap-profile-table.h"
#include "malloc_backtrace.h"

#ifndef	PATH_MAX
#ifdef MAXPATHLEN
#define	PATH_MAX	MAXPATHLEN
#else
#define	PATH_MAX	4096         // seems conservative for max filename len!
#endif
#endif

using tcmalloc::LowLevelAlloc;

//----------------------------------------------------------------------
// Flags that control heap-profiling
//
// The thread-safety of the profiler depends on these being immutable
// after main starts, so don't change them.
//----------------------------------------------------------------------

DEFINE_int64(heap_profile_allocation_interval,
             EnvToInt64("HEAP_PROFILE_ALLOCATION_INTERVAL", 1 << 30 /*1GB*/),
             "If non-zero, dump heap profiling information once every "
             "specified number of bytes allocated by the program since "
             "the last dump.");
DEFINE_int64(heap_profile_deallocation_interval,
             EnvToInt64("HEAP_PROFILE_DEALLOCATION_INTERVAL", 0),
             "If non-zero, dump heap profiling information once every "
             "specified number of bytes deallocated by the program "
             "since the last dump.");
// We could also add flags that report whenever inuse_bytes changes by
// X or -X, but there hasn't been a need for that yet, so we haven't.
DEFINE_int64(heap_profile_inuse_interval,
             EnvToInt64("HEAP_PROFILE_INUSE_INTERVAL", 100 << 20 /*100MB*/),
             "If non-zero, dump heap profiling information whenever "
             "the high-water memory usage mark increases by the specified "
             "number of bytes.");
DEFINE_int64(heap_profile_time_interval,
             EnvToInt64("HEAP_PROFILE_TIME_INTERVAL", 0),
             "If non-zero, dump heap profiling information once every "
             "specified number of seconds since the last dump.");


//----------------------------------------------------------------------
// Locking
//----------------------------------------------------------------------

// A pthread_mutex has way too much lock contention to be used here.
//
// I would like to use Mutex, but it can call malloc(),
// which can cause us to fall into an infinite recursion.
//
// So we use a simple spinlock.
static SpinLock heap_lock;

//----------------------------------------------------------------------
// Simple allocator for heap profiler's internal memory
//----------------------------------------------------------------------

static LowLevelAlloc::Arena *heap_profiler_memory;

static void* ProfilerMalloc(size_t bytes) {
  return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory);
}
static void ProfilerFree(void* p) {
  LowLevelAlloc::Free(p);
}

// We use buffers of this size in DoGetHeapProfile.


//----------------------------------------------------------------------
// Profiling control/state data
//----------------------------------------------------------------------

// Access to all of these is protected by heap_lock.
static bool  is_on;           // If are on as a subsytem.
static bool  dumping;         // Dumping status to prevent recursion
static char* filename_prefix; // Prefix used for profile file names
                              // (nullptr if no need for dumping yet)
static int   dump_count;      // How many dumps so far
static int64_t last_dump_alloc;  // alloc_size when did we last dump
static int64_t last_dump_free;   // free_size when did we last dump
static int64_t high_water_mark;  // In-use-bytes at last high-water dump
static int64_t last_dump_time;   // The time of the last dump

static HeapProfileTable* heap_profile;  // the heap profile table

//----------------------------------------------------------------------
// Profile generation
//----------------------------------------------------------------------

// Input must be a buffer of size at least 1MB.
static void DoDumpHeapProfileLocked(tcmalloc::GenericWriter* writer) {
  RAW_DCHECK(heap_lock.IsHeld(), "");
  if (is_on) {
    heap_profile->SaveProfile(writer);
  }
}

extern "C" char* GetHeapProfile() {
  tcmalloc::ChunkedWriterConfig config(ProfilerMalloc, ProfilerFree);

  return tcmalloc::WithWriterToStrDup(config, [] (tcmalloc::GenericWriter* writer) {
    SpinLockHolder l(&heap_lock);
    DoDumpHeapProfileLocked(writer);
  });
}

// defined below
static void NewHook(const void* ptr, size_t size);
static void DeleteHook(const void* ptr);

// Helper for HeapProfilerDump.
static void DumpProfileLocked(const char* reason) {
  RAW_DCHECK(heap_lock.IsHeld(), "");
  RAW_DCHECK(is_on, "");
  RAW_DCHECK(!dumping, "");

  if (filename_prefix == nullptr) return;  // we do not yet need dumping

  dumping = true;

  // Make file name
  char file_name[1000];
  dump_count++;
  snprintf(file_name, sizeof(file_name), "%s.%04d%s",
           filename_prefix, dump_count, HeapProfileTable::kFileExt);

  // Dump the profile
  RAW_VLOG(0, "Dumping heap profile to %s (%s)", file_name, reason);
  // We must use file routines that don't access memory, since we hold
  // a memory lock now.
  RawFD fd = RawOpenForWriting(file_name);
  if (fd == kIllegalRawFD) {
    RAW_LOG(ERROR, "Failed dumping heap profile to %s. Numeric errno is %d", file_name, errno);
    dumping = false;
    return;
  }

  using FileWriter = tcmalloc::RawFDGenericWriter<1 << 20>;
  FileWriter* writer = new (ProfilerMalloc(sizeof(FileWriter))) FileWriter(fd);

  DoDumpHeapProfileLocked(writer);

  // Note: as part of running destructor, it saves whatever stuff we left buffered in the writer
  writer->~FileWriter();
  ProfilerFree(writer);

  RawClose(fd);

  dumping = false;
}

//----------------------------------------------------------------------
// Profile collection
//----------------------------------------------------------------------

// Dump a profile after either an allocation or deallocation, if
// the memory use has changed enough since the last dump.
static void MaybeDumpProfileLocked() {
  if (!dumping) {
    const HeapProfileTable::Stats& total = heap_profile->total();
    const int64_t inuse_bytes = total.alloc_size - total.free_size;
    bool need_to_dump = false;
    char buf[128];

    if (FLAGS_heap_profile_allocation_interval > 0 &&
        total.alloc_size >=
        last_dump_alloc + FLAGS_heap_profile_allocation_interval) {
      snprintf(buf, sizeof(buf), ("%" PRId64 " MB allocated cumulatively, "
                                  "%" PRId64 " MB currently in use"),
               total.alloc_size >> 20, inuse_bytes >> 20);
      need_to_dump = true;
    } else if (FLAGS_heap_profile_deallocation_interval > 0 &&
               total.free_size >=
               last_dump_free + FLAGS_heap_profile_deallocation_interval) {
      snprintf(buf, sizeof(buf), ("%" PRId64 " MB freed cumulatively, "
                                  "%" PRId64 " MB currently in use"),
               total.free_size >> 20, inuse_bytes >> 20);
      need_to_dump = true;
    } else if (FLAGS_heap_profile_inuse_interval > 0 &&
               inuse_bytes >
               high_water_mark + FLAGS_heap_profile_inuse_interval) {
      snprintf(buf, sizeof(buf), "%" PRId64 " MB currently in use",
               inuse_bytes >> 20);
      need_to_dump = true;
    } else if (FLAGS_heap_profile_time_interval > 0 ) {
      int64_t current_time = time(nullptr);
      if (current_time - last_dump_time >=
          FLAGS_heap_profile_time_interval) {
        snprintf(buf, sizeof(buf), "%" PRId64 " sec since the last dump",
                 current_time - last_dump_time);
        need_to_dump = true;
        last_dump_time = current_time;
      }
    }
    if (need_to_dump) {
      DumpProfileLocked(buf);

      last_dump_alloc = total.alloc_size;
      last_dump_free = total.free_size;
      if (inuse_bytes > high_water_mark)
        high_water_mark = inuse_bytes;
    }
  }
}

//----------------------------------------------------------------------
// Allocation/deallocation hooks for MallocHook
//----------------------------------------------------------------------

// Record an allocation in the profile.
static void NewHook(const void* ptr, size_t bytes) {
  if (!ptr) return;

  // Take the stack trace outside the critical section.
  static constexpr int kDepth = 32;
  void* stack[kDepth];
  int depth = tcmalloc::GrabBacktrace(stack, kDepth, 1);
  SpinLockHolder l(&heap_lock);
  if (is_on) {
    heap_profile->RecordAlloc(ptr, bytes, depth, stack);
    MaybeDumpProfileLocked();
  }
}

// Record a deallocation in the profile.
static void DeleteHook(const void* ptr) {
  if (!ptr) return;

  SpinLockHolder l(&heap_lock);
  if (is_on) {
    heap_profile->RecordFree(ptr);
    MaybeDumpProfileLocked();
  }
}

//----------------------------------------------------------------------
// Starting/stopping/dumping
//----------------------------------------------------------------------

extern "C" void HeapProfilerStart(const char* prefix) {
  // A bit of a kludge. When we dump heap profiles on certain systems
  // (e.g. FreeBSD), we'll invoke GetProgramInvocationName and it'll
  // malloc. And we cannot malloc when under heap profiler lock(s). So
  // lets do it now (it caches the name internally).
  (void)tcmalloc::GetProgramInvocationName();

  SpinLockHolder l(&heap_lock);

  if (is_on) return;

  is_on = true;

  RAW_VLOG(0, "Starting tracking the heap");

  // This should be done before the hooks are set up, since it should
  // call new, and we want that to be accounted for correctly.
  MallocExtension::Initialize();

  heap_profiler_memory = LowLevelAlloc::NewArena();

  heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable)))
      HeapProfileTable(ProfilerMalloc, ProfilerFree);

  last_dump_alloc = 0;
  last_dump_free = 0;
  high_water_mark = 0;
  last_dump_time = 0;

  // We do not reset dump_count so if the user does a sequence of
  // HeapProfilerStart/HeapProfileStop, we will get a continuous
  // sequence of profiles.

  // Now set the hooks that capture new/delete and malloc/free.
  RAW_CHECK(MallocHook::AddNewHook(&NewHook), "");
  RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), "");

  // Copy filename prefix
  RAW_DCHECK(filename_prefix == nullptr, "");
  const int prefix_length = strlen(prefix);
  filename_prefix = reinterpret_cast(ProfilerMalloc(prefix_length + 1));
  memcpy(filename_prefix, prefix, prefix_length);
  filename_prefix[prefix_length] = '\0';
}

extern "C" int IsHeapProfilerRunning() {
  SpinLockHolder l(&heap_lock);
  return is_on ? 1 : 0;   // return an int, because C code doesn't have bool
}

extern "C" void HeapProfilerStop() {
  SpinLockHolder l(&heap_lock);

  if (!is_on) return;

  // Unset our new/delete hooks, checking they were set:
  RAW_CHECK(MallocHook::RemoveNewHook(&NewHook), "");
  RAW_CHECK(MallocHook::RemoveDeleteHook(&DeleteHook), "");

  // free profile
  heap_profile->~HeapProfileTable();
  ProfilerFree(heap_profile);
  heap_profile = nullptr;

  // free prefix
  ProfilerFree(filename_prefix);
  filename_prefix = nullptr;

  if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) {
    RAW_LOG(FATAL, "Memory leak in HeapProfiler:");
  }

  is_on = false;
}

extern "C" void HeapProfilerDump(const char *reason) {
  SpinLockHolder l(&heap_lock);
  if (is_on && !dumping) {
    DumpProfileLocked(reason);
  }
}

// Signal handler that is registered when a user selectable signal
// number is defined in the environment variable HEAPPROFILESIGNAL.
static void HeapProfilerDumpSignal(int signal_number) {
  (void)signal_number;
  if (!heap_lock.TryLock()) {
    return;
  }
  if (is_on && !dumping) {
    DumpProfileLocked("signal");
  }
  heap_lock.Unlock();
}


//----------------------------------------------------------------------
// Initialization/finalization code
//----------------------------------------------------------------------

// Initialization code
static void HeapProfilerInit() {
  // Everything after this point is for setting up the profiler based on envvar
  char fname[PATH_MAX];
  if (!GetUniquePathFromEnv("HEAPPROFILE", fname)) {
    return;
  }
  // We do a uid check so we don't write out files in a setuid executable.
#ifdef HAVE_GETEUID
  if (getuid() != geteuid()) {
    RAW_LOG(WARNING, ("HeapProfiler: ignoring HEAPPROFILE because "
                      "program seems to be setuid\n"));
    return;
  }
#endif

  char *signal_number_str = getenv("HEAPPROFILESIGNAL");
  if (signal_number_str != nullptr) {
    long int signal_number = strtol(signal_number_str, nullptr, 10);
    intptr_t old_signal_handler = reinterpret_cast(signal(signal_number, HeapProfilerDumpSignal));
    if (old_signal_handler == reinterpret_cast(SIG_ERR)) {
      RAW_LOG(FATAL, "Failed to set signal. Perhaps signal number %s is invalid\n", signal_number_str);
    } else if (old_signal_handler == 0) {
      RAW_LOG(INFO,"Using signal %d as heap profiling switch", signal_number);
    } else {
      RAW_LOG(FATAL, "Signal %d already in use\n", signal_number);
    }
  }

  HeapProfileTable::CleanupOldProfiles(fname);

  HeapProfilerStart(fname);
}

// class used for finalization -- dumps the heap-profile at program exit
struct HeapProfileEndWriter {
  ~HeapProfileEndWriter() {
    char buf[128];
    if (heap_profile) {
      const HeapProfileTable::Stats& total = heap_profile->total();
      const int64_t inuse_bytes = total.alloc_size - total.free_size;

      if ((inuse_bytes >> 20) > 0) {
        snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " MB in use"),
                 inuse_bytes >> 20);
      } else if ((inuse_bytes >> 10) > 0) {
        snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " kB in use"),
                 inuse_bytes >> 10);
      } else {
        snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " bytes in use"),
                 inuse_bytes);
      }
    } else {
      snprintf(buf, sizeof(buf), ("Exiting"));
    }
    HeapProfilerDump(buf);
  }
};

// We want to make sure tcmalloc is up and running before starting the profiler
static const TCMallocGuard tcmalloc_initializer;
REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit());
static HeapProfileEndWriter heap_profile_end_writer;
gperftools-gperftools-2.18/src/internal_logging.cc000066400000000000000000000117131513545575200224510ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Sanjay Ghemawat 

#include 
#include "internal_logging.h"
#include                      // for va_end, va_start
#include                       // for vsnprintf, va_list, etc
#include                      // for abort
#include                      // for strlen, memcpy
#ifdef HAVE_UNISTD_H
#include     // for write()
#endif

#include 
#include "base/logging.h"

namespace tcmalloc {

static void WriteMessage(const char* msg, int length) {
  WRITE_TO_STDERR(msg, length);
}

class Logger {
 public:
  bool Add(const LogItem& item);
  bool AddStr(const char* str, int n);
  bool AddNum(uint64_t num, int base);  // base must be 10 or 16.

  static const int kBufSize = 200;
  char* p_;
  char* end_;
  char buf_[kBufSize];
};

void Log(LogMode mode, const char* filename, int line,
         LogItem a, LogItem b, LogItem c, LogItem d) {
  Logger state;
  state.p_ = state.buf_;
  state.end_ = state.buf_ + sizeof(state.buf_);
  state.AddStr(filename, strlen(filename))
      && state.AddStr(":", 1)
      && state.AddNum(line, 10)
      && state.AddStr("]", 1)
      && state.Add(a)
      && state.Add(b)
      && state.Add(c)
      && state.Add(d);

  // Teminate with newline
  if (state.p_ >= state.end_) {
    state.p_ = state.end_ - 1;
  }
  *state.p_ = '\n';
  state.p_++;

  int msglen = state.p_ - state.buf_;
  if (mode == kLog) {
    WriteMessage(state.buf_, msglen);
    return;
  }

  WriteMessage(state.buf_, msglen);

#if defined(__has_builtin)
#if __has_builtin(__builtin_trap)
  __builtin_trap();
#endif
#endif  // defined(__has_builtin)

  abort();
}

bool Logger::Add(const LogItem& item) {
  // Separate items with spaces
  if (p_ < end_) {
    *p_ = ' ';
    p_++;
  }

  switch (item.tag_) {
    case LogItem::kStr:
      return AddStr(item.u_.str, strlen(item.u_.str));
    case LogItem::kUnsigned:
      return AddNum(item.u_.unum, 10);
    case LogItem::kSigned:
      if (item.u_.snum < 0) {
        // The cast to uint64_t is intentionally before the negation
        // so that we do not attempt to negate -2^63.
        return AddStr("-", 1)
            && AddNum(- static_cast(item.u_.snum), 10);
      } else {
        return AddNum(static_cast(item.u_.snum), 10);
      }
    case LogItem::kPtr:
      return AddStr("0x", 2)
          && AddNum(reinterpret_cast(item.u_.ptr), 16);
    default:
      return false;
  }
}

bool Logger::AddStr(const char* str, int n) {
  if (end_ - p_ < n) {
    return false;
  } else {
    memcpy(p_, str, n);
    p_ += n;
    return true;
  }
}

bool Logger::AddNum(uint64_t num, int base) {
  static const char kDigits[] = "0123456789abcdef";
  char space[22];  // more than enough for 2^64 in smallest supported base (10)
  char* end = space + sizeof(space);
  char* pos = end;
  do {
    pos--;
    *pos = kDigits[num % base];
    num /= base;
  } while (num > 0 && pos > space);
  return AddStr(pos, end - pos);
}

}  // end tcmalloc namespace

void TCMalloc_Printer::printf(const char* format, ...) {
  if (left_ > 0) {
    va_list ap;
    va_start(ap, format);
    const int r = vsnprintf(buf_, left_, format, ap);
    va_end(ap);
    if (r < 0) {
      // Some kind of error
      left_ = 0;
    } else if (r > left_) {
      // Truncation
      left_ = 0;
    } else {
      left_ -= r;
      buf_ += r;
    }
  }
}
gperftools-gperftools-2.18/src/internal_logging.h000066400000000000000000000122511513545575200223110ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 
//
// Internal logging and related utility routines.

#ifndef TCMALLOC_INTERNAL_LOGGING_H_
#define TCMALLOC_INTERNAL_LOGGING_H_

#include 
#include                      // for size_t
#include 

//-------------------------------------------------------------------
// Utility routines
//-------------------------------------------------------------------

// Safe logging helper: we write directly to the stderr file
// descriptor and avoid FILE buffering because that may invoke
// malloc().
//
// Example:
//   Log(kLog, __FILE__, __LINE__, "error", bytes);

namespace tcmalloc {
enum LogMode {
  kLog,                       // Just print the message
  kCrash,                     // Print the message and crash
};

class Logger;

// A LogItem holds any of the argument types that can be passed to Log()
class LogItem {
 public:
  LogItem()                     : tag_(kEnd)      { }
  LogItem(const char* v)        : tag_(kStr)      { u_.str = v; }
  LogItem(int v)                : tag_(kSigned)   { u_.snum = v; }
  LogItem(long v)               : tag_(kSigned)   { u_.snum = v; }
  LogItem(long long v)          : tag_(kSigned)   { u_.snum = v; }
  LogItem(unsigned int v)       : tag_(kUnsigned) { u_.unum = v; }
  LogItem(unsigned long v)      : tag_(kUnsigned) { u_.unum = v; }
  LogItem(unsigned long long v) : tag_(kUnsigned) { u_.unum = v; }
  LogItem(const void* v)        : tag_(kPtr)      { u_.ptr = v; }
 private:
  friend class Logger;
  enum Tag {
    kStr,
    kSigned,
    kUnsigned,
    kPtr,
    kEnd
  };
  Tag tag_;
  union {
    const char* str;
    const void* ptr;
    int64_t snum;
    uint64_t unum;
  } u_;
};

extern void Log(LogMode mode, const char* filename, int line,
                LogItem a, LogItem b = LogItem(),
                LogItem c = LogItem(), LogItem d = LogItem());

}  // end tcmalloc namespace

// Like assert(), but executed even in NDEBUG mode
#undef CHECK_CONDITION
#define CHECK_CONDITION(cond)                                            \
do {                                                                     \
  if (!(cond)) {                                                         \
    ::tcmalloc::Log(::tcmalloc::kCrash, __FILE__, __LINE__, #cond);      \
    for (;;) {} /* unreachable */                                        \
  }                                                                      \
} while (0)

#define CHECK_CONDITION_PRINT(cond, str)                            \
  do {                                                              \
    if (!(cond)) {                                                  \
      ::tcmalloc::Log(::tcmalloc::kCrash, __FILE__, __LINE__, str); \
    }                                                               \
  } while (0)

// Our own version of assert() so we can avoid hanging by trying to do
// all kinds of goofy printing while holding the malloc lock.
#ifndef NDEBUG
#define ASSERT(cond) CHECK_CONDITION(cond)
#define ASSERT_PRINT(cond, str) CHECK_CONDITION_PRINT(cond, str)
#else
#define ASSERT(cond) ((void) 0)
#define ASSERT_PRINT(cond, str) ((void)0)
#endif

// Print into buffer
class TCMalloc_Printer {
 private:
  char* buf_;           // Where should we write next
  int   left_;          // Space left in buffer (including space for \0)

 public:
  // REQUIRES: "length > 0"
  TCMalloc_Printer(char* buf, int length) : buf_(buf), left_(length) {
    buf[0] = '\0';
  }

  void printf(const char* format, ...)
#ifdef HAVE___ATTRIBUTE__
    __attribute__ ((__format__ (__printf__, 2, 3)))
#endif
;
};

#endif  // TCMALLOC_INTERNAL_LOGGING_H_
gperftools-gperftools-2.18/src/libbacktrace_api.h000066400000000000000000000110021513545575200222170ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef LIBBACKTRACE_API_H_
#define LIBBACKTRACE_API_H_

#include 
#include 

extern "C" {

// those are originally declared in libbacktrace/backtrace.h, but lets
// declare only the subset and renamed function names that we use. Our
// backtrace-integration contract is to maintain it to match
// libbacktrace's definitions.

struct backtrace_state;
typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
					const char *filename, int lineno,
					const char *function);
typedef void (*backtrace_error_callback) (void *data, const char *msg,
					  int errnum);

struct backtrace_state *tcmalloc_backtrace_create_state(
  const char *filename, int threaded,
  backtrace_error_callback error_callback, void *data);

int tcmalloc_backtrace_pcinfo(
  struct backtrace_state *state, uintptr_t pc,
  backtrace_full_callback callback,
  backtrace_error_callback error_callback,
  void *data);

typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc,
					    const char *symname,
					    uintptr_t symval,
					    uintptr_t symsize);

int tcmalloc_backtrace_syminfo(struct backtrace_state *state, uintptr_t addr,
                               backtrace_syminfo_callback callback,
                               backtrace_error_callback error_callback,
                               void *data);

// backtrace-alloc.cc

// This is part of our "special sauce" that lets is release all memory
// allocated by libbacktrace state instance. We rely on some
// implementation details.
void tcmalloc_backtrace_dispose_state(struct backtrace_state* state);

// This is originally defined in internal.h which we cannot include here.
//
// This is internal libbacktrace api used to allocate memory. We
// replace their implementation with ours (based on low_level_alloc
// facility) and with extra feature of being able to mass-free all of
// it.
struct backtrace_vector
{
  /* The base of the vector.  */
  void *base;
  /* The number of bytes in the vector.  */
  size_t size;
  /* The number of bytes available at the current allocation.  */
  size_t alc;
};

extern void *tcmalloc_backtrace_alloc(
  struct backtrace_state *state, size_t size,
  backtrace_error_callback error_callback,
  void *data);

extern void tcmalloc_backtrace_free(
  struct backtrace_state *state, void *mem,
  size_t size,
  backtrace_error_callback error_callback,
  void *data);

extern void *tcmalloc_backtrace_vector_grow(
  struct backtrace_state *state, size_t size,
  backtrace_error_callback error_callback,
  void *data,
  struct backtrace_vector *vec);

extern void* tcmalloc_backtrace_vector_finish (
  struct backtrace_state *state,
  struct backtrace_vector *vec,
  backtrace_error_callback error_callback,
  void *data);

extern int tcmalloc_backtrace_vector_release (
  struct backtrace_state *state,
  struct backtrace_vector *vec,
  backtrace_error_callback error_callback,
  void *data);

}  // extern "C"


#endif  // LIBBACKTRACE_API_H_
gperftools-gperftools-2.18/src/libc_override.h000066400000000000000000000111761513545575200216040ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein 
//
// This .h file imports the code that causes tcmalloc to override libc
// versions of malloc/free/new/delete/etc.  That is, it provides the
// logic that makes it so calls to malloc(10) go through tcmalloc,
// rather than the default (libc) malloc.
//
// This file also provides a method: ReplaceSystemAlloc(), that every
// libc_override_*.h file it #includes is required to provide.  This
// is called when first setting up tcmalloc -- that is, when a global
// constructor in tcmalloc.cc is executed -- to do any initialization
// work that may be required for this OS.  (Note we cannot entirely
// control when tcmalloc is initialized, and the system may do some
// mallocs and frees before this routine is called.)  It may be a
// noop.
//
// Every libc has its own way of doing this, and sometimes the compiler
// matters too, so we have a different file for each libc, and often
// for different compilers and OS's.

#ifndef TCMALLOC_LIBC_OVERRIDE_INL_H_
#define TCMALLOC_LIBC_OVERRIDE_INL_H_

#include 
#ifdef HAVE_FEATURES_H
#include    // for __GLIBC__
#endif
#include 

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
#define CPP_NOTHROW noexcept
#define CPP_BADALLOC
#else
#define CPP_NOTHROW throw()
#define CPP_BADALLOC throw(std::bad_alloc)
#endif

#if defined(__has_feature)
#  if __has_feature(address_sanitizer) || __has_feature(memory_sanitizer) || __has_feature(thread_sanitizer)
#    define TCMALLOC_UNDER_SANITIZER
#  endif
#elif defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__)
#  define TCMALLOC_UNDER_SANITIZER
#endif

// A number of sanitizers are incompatible with tcmalloc. So lets
// disable normal memory allocation overrides under those sanitizers.
#if defined(TCMALLOC_UNDER_SANITIZER) && !defined(TCMALLOC_SKIP_OVERRIDE)
#define TCMALLOC_SKIP_OVERRIDE
#endif

#ifdef TCMALLOC_SKIP_OVERRIDE
static void ReplaceSystemAlloc() {}

#else // !TCMALLOC_SKIP_OVERRIDE

static void ReplaceSystemAlloc();  // defined in the .h files below

// For windows, there are two ways to get tcmalloc.  If we're
// patching, then src/windows/patch_function.cc will do the necessary
// overriding here.  Otherwise, we doing the 'redefine' trick, where
// we remove malloc/new/etc from mscvcrt.dll, and just need to define
// them now.
#if defined(_WIN32) && defined(WIN32_DO_PATCHING)
void PatchWindowsFunctions();   // in src/windows/patch_function.cc
static void ReplaceSystemAlloc() { PatchWindowsFunctions(); }

#elif defined(_WIN32) && !defined(WIN32_DO_PATCHING)
#include "libc_override_redefine.h"

#elif defined(__APPLE__)
#include "libc_override_osx.h"

#elif defined(__GLIBC__)
#include "libc_override_glibc.h"

// Not all gcc systems necessarily support weak symbols, but all the
// ones I know of do, so for now just assume they all do.
#elif defined(__GNUC__)
#include "libc_override_gcc_and_weak.h"

#else
#error Need to add support for your libc/OS here

#endif

#endif  // !TCMALLOC_SKIP_OVERRIDE

#endif  // TCMALLOC_LIBC_OVERRIDE_INL_H_
gperftools-gperftools-2.18/src/libc_override_aix.h000066400000000000000000000055031513545575200224420ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2021, IBM Ltd.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Chris Cambly 
//
// Used to override malloc routines on AIX

#ifndef TCMALLOC_LIBC_OVERRIDE_AIX_INL_H_
#define TCMALLOC_LIBC_OVERRIDE_AIX_INL_H_

#ifndef _AIX
# error libc_override_aix.h is for AIX systems only.
#endif

extern "C" {
  // AIX user-defined malloc replacement routines
  void* __malloc__(size_t size) __THROW               ALIAS(tc_malloc);
  void __free__(void* ptr) __THROW                    ALIAS(tc_free);
  void* __realloc__(void* ptr, size_t size) __THROW   ALIAS(tc_realloc);
  void* __calloc__(size_t n, size_t size) __THROW     ALIAS(tc_calloc);
  int __posix_memalign__(void** r, size_t a, size_t s) __THROW ALIAS(tc_posix_memalign);
  int __mallopt__(int cmd, int value) __THROW         ALIAS(tc_mallopt);
#ifdef HAVE_STRUCT_MALLINFO
  struct mallinfo __mallinfo__(void) __THROW          ALIAS(tc_mallinfo);
#endif
#ifdef HAVE_STRUCT_MALLINFO2
  struct mallinfo2 __mallinfo2__(void) __THROW        ALIAS(tc_mallinfo2);
#endif
  void __malloc_init__(void)               { tc_free(tc_malloc(1));}
  void* __malloc_prefork_lock__(void)      { /* nothing to lock */ }
  void* __malloc_postfork_unlock__(void)   { /* nothing to unlock */}
}   // extern "C"

#endif  // TCMALLOC_LIBC_OVERRIDE_AIX_INL_H_
gperftools-gperftools-2.18/src/libc_override_gcc_and_weak.h000066400000000000000000000231611513545575200242460ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein 
//
// Used to override malloc routines on systems that define the
// memory allocation routines to be weak symbols in their libc
// (almost all unix-based systems are like this), on gcc, which
// suppports the 'alias' attribute.

#ifndef TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_
#define TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_

#ifdef HAVE_SYS_CDEFS_H
#include     // for __THROW
#endif
#include 

#include "getenv_safe.h" // TCMallocGetenvSafe
#include "base/commandlineflags.h"

#ifndef __THROW    // I guess we're not on a glibc-like system
# define __THROW   // __THROW is just an optimization, so ok to make it ""
#endif

#ifndef __GNUC__
# error libc_override_gcc_and_weak.h is for gcc distributions only.
#endif

#define ALIAS(tc_fn)   __attribute__ ((alias (#tc_fn), used)) PERFTOOLS_DLL_DECL

void* operator new(size_t size) CPP_BADALLOC  ALIAS(tc_new);
void operator delete(void* p) CPP_NOTHROW     ALIAS(tc_delete);
void* operator new[](size_t size) CPP_BADALLOC ALIAS(tc_newarray);
void operator delete[](void* p) CPP_NOTHROW   ALIAS(tc_deletearray);
void* operator new(size_t size, const std::nothrow_t& nt) CPP_NOTHROW
                                              ALIAS(tc_new_nothrow);
void* operator new[](size_t size, const std::nothrow_t& nt) CPP_NOTHROW
                                              ALIAS(tc_newarray_nothrow);
void operator delete(void* p, const std::nothrow_t& nt) CPP_NOTHROW
                                              ALIAS(tc_delete_nothrow);
void operator delete[](void* p, const std::nothrow_t& nt) CPP_NOTHROW
                                              ALIAS(tc_deletearray_nothrow);

#if defined(ENABLE_SIZED_DELETE)

void operator delete(void *p, size_t size) CPP_NOTHROW
    ALIAS(tc_delete_sized);
void operator delete[](void *p, size_t size) CPP_NOTHROW
    ALIAS(tc_deletearray_sized);

#elif defined(ENABLE_DYNAMIC_SIZED_DELETE) && \
  (__GNUC__ * 100 + __GNUC_MINOR__) >= 405

static void delegate_sized_delete(void *p, size_t s) {
  (operator delete)(p);
}

static void delegate_sized_deletearray(void *p, size_t s) {
  (operator delete[])(p);
}

extern "C" __attribute__((weak))
int tcmalloc_sized_delete_enabled(void);

static bool sized_delete_enabled(void) {
  if (tcmalloc_sized_delete_enabled != 0) {
    return !!tcmalloc_sized_delete_enabled();
  }

  const char *flag = TCMallocGetenvSafe("TCMALLOC_ENABLE_SIZED_DELETE");
  return tcmalloc::commandlineflags::StringToBool(flag, false);
}

extern "C" {

static void *resolve_delete_sized(void) {
  if (sized_delete_enabled()) {
    return reinterpret_cast(tc_delete_sized);
  }
  return reinterpret_cast(delegate_sized_delete);
}

static void *resolve_deletearray_sized(void) {
  if (sized_delete_enabled()) {
    return reinterpret_cast(tc_deletearray_sized);
  }
  return reinterpret_cast(delegate_sized_deletearray);
}

}

void operator delete(void *p, size_t size) CPP_NOTHROW
  __attribute__((ifunc("resolve_delete_sized")));
void operator delete[](void *p, size_t size) CPP_NOTHROW
  __attribute__((ifunc("resolve_deletearray_sized")));

#else /* !ENABLE_SIZED_DELETE && !ENABLE_DYN_SIZED_DELETE */

void operator delete(void *p, size_t size) CPP_NOTHROW
  ALIAS(tc_delete_sized);
void operator delete[](void *p, size_t size) CPP_NOTHROW
  ALIAS(tc_deletearray_sized);

#endif /* !ENABLE_SIZED_DELETE && !ENABLE_DYN_SIZED_DELETE */

void* operator new(size_t size, std::align_val_t al)
    ALIAS(tc_new_aligned);
void operator delete(void* p, std::align_val_t al) CPP_NOTHROW
    ALIAS(tc_delete_aligned);
void* operator new[](size_t size, std::align_val_t al)
    ALIAS(tc_newarray_aligned);
void operator delete[](void* p, std::align_val_t al) CPP_NOTHROW
    ALIAS(tc_deletearray_aligned);
void* operator new(size_t size, std::align_val_t al, const std::nothrow_t& nt) CPP_NOTHROW
    ALIAS(tc_new_aligned_nothrow);
void* operator new[](size_t size, std::align_val_t al, const std::nothrow_t& nt) CPP_NOTHROW
    ALIAS(tc_newarray_aligned_nothrow);
void operator delete(void* p, std::align_val_t al, const std::nothrow_t& nt) CPP_NOTHROW
    ALIAS(tc_delete_aligned_nothrow);
void operator delete[](void* p, std::align_val_t al, const std::nothrow_t& nt) CPP_NOTHROW
    ALIAS(tc_deletearray_aligned_nothrow);

#if defined(ENABLE_SIZED_DELETE)

void operator delete(void *p, size_t size, std::align_val_t al) CPP_NOTHROW
    ALIAS(tc_delete_sized_aligned);
void operator delete[](void *p, size_t size, std::align_val_t al) CPP_NOTHROW
    ALIAS(tc_deletearray_sized_aligned);

#else /* defined(ENABLE_SIZED_DELETE) */

#if defined(ENABLE_DYNAMIC_SIZED_DELETE) && \
  (__GNUC__ * 100 + __GNUC_MINOR__) >= 405

static void delegate_sized_aligned_delete(void *p, size_t s, std::align_val_t al) {
  (operator delete)(p, al);
}

static void delegate_sized_aligned_deletearray(void *p, size_t s, std::align_val_t al) {
  (operator delete[])(p, al);
}

extern "C" {

static void *resolve_delete_sized_aligned(void) {
  if (sized_delete_enabled()) {
    return reinterpret_cast(tc_delete_sized_aligned);
  }
  return reinterpret_cast(delegate_sized_aligned_delete);
}

static void *resolve_deletearray_sized_aligned(void) {
  if (sized_delete_enabled()) {
    return reinterpret_cast(tc_deletearray_sized_aligned);
  }
  return reinterpret_cast(delegate_sized_aligned_deletearray);
}

}

void operator delete(void *p, size_t size, std::align_val_t al) CPP_NOTHROW
  __attribute__((ifunc("resolve_delete_sized_aligned")));
void operator delete[](void *p, size_t size, std::align_val_t al) CPP_NOTHROW
  __attribute__((ifunc("resolve_deletearray_sized_aligned")));

#else /* defined(ENABLE_DYN_SIZED_DELETE) */

void operator delete(void *p, size_t size, std::align_val_t al) CPP_NOTHROW
  ALIAS(tc_delete_sized_aligned);
void operator delete[](void *p, size_t size, std::align_val_t al) CPP_NOTHROW
  ALIAS(tc_deletearray_sized_aligned);

#endif /* defined(ENABLE_DYN_SIZED_DELETE) */

#endif /* defined(ENABLE_SIZED_DELETE) */

extern "C" {
  void* malloc(size_t size) __THROW               ALIAS(tc_malloc);
  void free(void* ptr) __THROW                    ALIAS(tc_free);
  void* realloc(void* ptr, size_t size) __THROW   ALIAS(tc_realloc);
  void* calloc(size_t n, size_t size) __THROW     ALIAS(tc_calloc);
#if __QNXNTO__
  // QNX has crazy cfree declaration
  int cfree(void* ptr) { tc_cfree(ptr); return 0; }
#else
  void cfree(void* ptr) __THROW                   ALIAS(tc_cfree);
#endif
  void* memalign(size_t align, size_t s) __THROW  ALIAS(tc_memalign);
  void* aligned_alloc(size_t align, size_t s) __THROW ALIAS(tc_memalign);
  void* valloc(size_t size) __THROW               ALIAS(tc_valloc);
  void* pvalloc(size_t size) __THROW              ALIAS(tc_pvalloc);
  int posix_memalign(void** r, size_t a, size_t s) __THROW
      ALIAS(tc_posix_memalign);
#ifndef __UCLIBC__
  void malloc_stats(void) __THROW                 ALIAS(tc_malloc_stats);
#endif
#if __QNXNTO__
  int mallopt(int, intptr_t) ALIAS(tc_mallopt);
#else
  int mallopt(int cmd, int value) __THROW         ALIAS(tc_mallopt);
#endif
#ifdef HAVE_STRUCT_MALLINFO
  struct mallinfo mallinfo(void) __THROW          ALIAS(tc_mallinfo);
#endif
#ifdef HAVE_STRUCT_MALLINFO2
  struct mallinfo2 mallinfo2(void) __THROW        ALIAS(tc_mallinfo2);
#endif
  size_t malloc_size(void* p) __THROW             ALIAS(tc_malloc_size);
#if defined(__ANDROID__)
  size_t malloc_usable_size(const void* p) __THROW
         ALIAS(tc_malloc_size);
#else
  size_t malloc_usable_size(void* p) __THROW      ALIAS(tc_malloc_size);
#endif

  // C23
  void free_sized(void* p, size_t size) __THROW ALIAS(tc_free_sized);
  void free_aligned_sized(void* p, size_t align, size_t size) __THROW ALIAS(tc_free_aligned_sized);
}   // extern "C"

/* AIX User-defined malloc replacement interface overrides */
#if defined(_AIX)
#include "libc_override_aix.h"
#endif

#undef ALIAS

// No need to do anything at tcmalloc-registration time: we do it all
// via overriding weak symbols (at link time).
static void ReplaceSystemAlloc() { }

#endif  // TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_
gperftools-gperftools-2.18/src/libc_override_glibc.h000066400000000000000000000102151513545575200227350ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein 
//
// Used to override malloc routines on systems that are using glibc.

#ifndef TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_
#define TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_

#include 
#include      // for __GLIBC__
#include 

#ifndef __GLIBC__
# error libc_override_glibc.h is for glibc distributions only.
#endif

// In glibc, the memory-allocation methods are weak symbols, so we can
// just override them with our own.  If we're using gcc, we can use
// __attribute__((alias)) to do the overriding easily (exception:
// Mach-O, which doesn't support aliases).  Otherwise we have to use a
// function call.
#if !defined(__GNUC__) || defined(__MACH__)

// This also defines ReplaceSystemAlloc().
# include "libc_override_redefine.h"  // defines functions malloc()/etc

#else  // #if !defined(__GNUC__) || defined(__MACH__)

// If we get here, we're a gcc system, so do all the overriding we do
// with gcc.  This does the overriding of all the 'normal' memory
// allocation.  This also defines ReplaceSystemAlloc().
# include "libc_override_gcc_and_weak.h"

// We also have to do some glibc-specific overriding.  Some library
// routines on RedHat 9 allocate memory using malloc() and free it
// using __libc_free() (or vice-versa).  Since we provide our own
// implementations of malloc/free, we need to make sure that the
// __libc_XXX variants (defined as part of glibc) also point to the
// same implementations.  Since it only matters for redhat, we
// do it inside the gcc #ifdef, since redhat uses gcc.
// TODO(csilvers): only do this if we detect we're an old enough glibc?

#define ALIAS(tc_fn)   __attribute__ ((alias (#tc_fn))) PERFTOOLS_DLL_DECL
extern "C" {
  void* __libc_malloc(size_t size)                ALIAS(tc_malloc);
  void __libc_free(void* ptr)                     ALIAS(tc_free);
  void* __libc_realloc(void* ptr, size_t size)    ALIAS(tc_realloc);
  void* __libc_calloc(size_t n, size_t size)      ALIAS(tc_calloc);
  void __libc_cfree(void* ptr)                    ALIAS(tc_cfree);
  void* __libc_memalign(size_t align, size_t s)   ALIAS(tc_memalign);
  void* __libc_valloc(size_t size)                ALIAS(tc_valloc);
  void* __libc_pvalloc(size_t size)               ALIAS(tc_pvalloc);
  int __posix_memalign(void** r, size_t a, size_t s)  ALIAS(tc_posix_memalign);
}   // extern "C"
#undef ALIAS

#endif  // #if defined(__GNUC__) && !defined(__MACH__)

// No need to write ReplaceSystemAlloc(); one of the #includes above
// did it for us.

#endif  // TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_
gperftools-gperftools-2.18/src/libc_override_osx.h000066400000000000000000000347671513545575200225100ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein 
//
// Used to override malloc routines on OS X systems.  We use the
// malloc-zone functionality built into OS X to register our malloc
// routine.
//
// 1) We used to use the normal 'override weak libc malloc/etc'
// technique for OS X.  This is not optimal because mach does not
// support the 'alias' attribute, so we had to have forwarding
// functions.  It also does not work very well with OS X shared
// libraries (dylibs) -- in general, the shared libs don't use
// tcmalloc unless run with the DYLD_FORCE_FLAT_NAMESPACE envvar.
//
// 2) Another approach would be to use an interposition array:
//      static const interpose_t interposers[] __attribute__((section("__DATA, __interpose"))) = {
//        { (void *)tc_malloc, (void *)malloc },
//        { (void *)tc_free, (void *)free },
//      };
// This requires the user to set the DYLD_INSERT_LIBRARIES envvar, so
// is not much better.
//
// 3) Registering a new malloc zone avoids all these issues:
//  http://www.opensource.apple.com/source/Libc/Libc-583/include/malloc/malloc.h
//  http://www.opensource.apple.com/source/Libc/Libc-583/gen/malloc.c
// If we make tcmalloc the default malloc zone (undocumented but
// possible) then all new allocs use it, even those in shared
// libraries.  Allocs done before tcmalloc was installed, or in libs
// that aren't using tcmalloc for some reason, will correctly go
// through the malloc-zone interface when free-ing, and will pick up
// the libc free rather than tcmalloc free.  So it should "never"
// cause a crash (famous last words).
//
// 4) The routines one must define for one's own malloc have changed
// between OS X versions.  This requires some hoops on our part, but
// is only really annoying when it comes to posix_memalign.  The right
// behavior there depends on what OS version tcmalloc was compiled on,
// but also what OS version the program is running on.  For now, we
// punt and don't implement our own posix_memalign.  Apps that really
// care can use tc_posix_memalign directly.

#ifndef TCMALLOC_LIBC_OVERRIDE_OSX_INL_H_
#define TCMALLOC_LIBC_OVERRIDE_OSX_INL_H_

#include 
#ifdef HAVE_FEATURES_H
#include 
#endif
#include 

#if !defined(__APPLE__)
# error libc_override_glibc-osx.h is for OS X distributions only.
#endif

#include 
#include 

#include 

namespace tcmalloc {
  void CentralCacheLockAll();
  void CentralCacheUnlockAll();
}

// from AvailabilityMacros.h
#if defined(MAC_OS_X_VERSION_10_6) && \
    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
extern "C" {
  // This function is only available on 10.6 (and later) but the
  // LibSystem headers do not use AvailabilityMacros.h to handle weak
  // importing automatically.  This prototype is a copy of the one in
  //  with the WEAK_IMPORT_ATTRBIUTE added.
  extern malloc_zone_t *malloc_default_purgeable_zone(void)
      WEAK_IMPORT_ATTRIBUTE;
}
#endif

// We need to provide wrappers around all the libc functions.
namespace {
size_t mz_size(malloc_zone_t* zone, const void* ptr) {
  // Note, this does not work for emergency malloc's memory. And in
  // principle OSX doesn't need or use it. But by default we enable
  // it, so that our unit test coverage is wider.
  if (MallocExtension::instance()->GetOwnership(ptr) != MallocExtension::kOwned)
    return 0;  // malloc_zone semantics: return 0 if we don't own the memory

  // TODO(csilvers): change this method to take a const void*, one day.
  return MallocExtension::instance()->GetAllocatedSize(const_cast(ptr));
}

ATTRIBUTE_NOINLINE void* mz_malloc(malloc_zone_t* zone, size_t size) {
  return tc_malloc(size);
}

ATTRIBUTE_NOINLINE void* mz_calloc(malloc_zone_t* zone, size_t num_items, size_t size) {
  return tc_calloc(num_items, size);
}

ATTRIBUTE_NOINLINE void* mz_valloc(malloc_zone_t* zone, size_t size) {
  return tc_valloc(size);
}

ATTRIBUTE_NOINLINE void mz_free(malloc_zone_t* zone, void* ptr) {
  return tc_free(ptr);
}

ATTRIBUTE_NOINLINE void mz_free_definite_size(malloc_zone_t* zone, void *ptr, size_t size) {
  return tc_free(ptr);
}

ATTRIBUTE_NOINLINE void* mz_realloc(malloc_zone_t* zone, void* ptr, size_t size) {
  return tc_realloc(ptr, size);
}

ATTRIBUTE_NOINLINE void* mz_memalign(malloc_zone_t* zone, size_t align, size_t size) {
  return tc_memalign(align, size);
}

void mz_destroy(malloc_zone_t* zone) {
  // A no-op -- we will not be destroyed!
}

// malloc_introspection callbacks.  I'm not clear on what all of these do.
kern_return_t mi_enumerator(task_t task, void *,
                            unsigned type_mask, vm_address_t zone_address,
                            memory_reader_t reader,
                            vm_range_recorder_t recorder) {
  // Should enumerate all the pointers we have.  Seems like a lot of work.
  return KERN_FAILURE;
}

size_t mi_good_size(malloc_zone_t *zone, size_t size) {
  // I think it's always safe to return size, but we maybe could do better.
  return size;
}

boolean_t mi_check(malloc_zone_t *zone) {
  return MallocExtension::instance()->VerifyAllMemory();
}

void mi_print(malloc_zone_t *zone, boolean_t verbose) {
  int bufsize = 8192;
  if (verbose)
    bufsize = 102400;   // I picked this size arbitrarily
  char* buffer = new char[bufsize];
  MallocExtension::instance()->GetStats(buffer, bufsize);
  fprintf(stdout, "%s", buffer);
  delete[] buffer;
}

void mi_log(malloc_zone_t *zone, void *address) {
  // I don't think we support anything like this
}

void mi_force_lock(malloc_zone_t *zone) {
  tcmalloc::CentralCacheLockAll();
}

void mi_force_unlock(malloc_zone_t *zone) {
  tcmalloc::CentralCacheUnlockAll();
}

void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
  // TODO(csilvers): figure out how to fill these out
  stats->blocks_in_use = 0;
  stats->size_in_use = 0;
  stats->max_size_in_use = 0;
  stats->size_allocated = 0;
}

boolean_t mi_zone_locked(malloc_zone_t *zone) {
  return false;  // Hopefully unneeded by us!
}

}  // unnamed namespace

// OS X doesn't have pvalloc, cfree, malloc_statc, etc, so we can just
// define our own. :-)  OS X supplies posix_memalign in some versions
// but not others, either strongly or weakly linked, in a way that's
// difficult enough to code to correctly, that I just don't try to
// support either memalign() or posix_memalign().  If you need them
// and are willing to code to tcmalloc, you can use tc_posix_memalign().
extern "C" {
  void  cfree(void* p)                   { tc_cfree(p);               }
  void* pvalloc(size_t s)                { return tc_pvalloc(s);      }
  void malloc_stats(void)                { tc_malloc_stats();         }
  int mallopt(int cmd, int v)            { return tc_mallopt(cmd, v); }
  // No struct mallinfo on OS X, so don't define mallinfo().
  // An alias for malloc_size(), which OS X defines.
  size_t malloc_usable_size(void* p)     { return tc_malloc_size(p); }
}  // extern "C"

static malloc_zone_t *get_default_zone() {
   malloc_zone_t **zones = nullptr;
   unsigned int num_zones = 0;

   /*
    * On OSX 10.12, malloc_default_zone returns a special zone that is not
    * present in the list of registered zones. That zone uses a "lite zone"
    * if one is present (apparently enabled when malloc stack logging is
    * enabled), or the first registered zone otherwise. In practice this
    * means unless malloc stack logging is enabled, the first registered
    * zone is the default.
    * So get the list of zones to get the first one, instead of relying on
    * malloc_default_zone.
    */
   if (KERN_SUCCESS != malloc_get_all_zones(0, nullptr, (vm_address_t**) &zones,
                                            &num_zones)) {
       /* Reset the value in case the failure happened after it was set. */
       num_zones = 0;
   }

   if (num_zones)
     return zones[0];

   return malloc_default_zone();
}


static void ReplaceSystemAlloc() {
  static malloc_introspection_t tcmalloc_introspection;
  memset(&tcmalloc_introspection, 0, sizeof(tcmalloc_introspection));

  tcmalloc_introspection.enumerator = &mi_enumerator;
  tcmalloc_introspection.good_size = &mi_good_size;
  tcmalloc_introspection.check = &mi_check;
  tcmalloc_introspection.print = &mi_print;
  tcmalloc_introspection.log = &mi_log;
  tcmalloc_introspection.force_lock = &mi_force_lock;
  tcmalloc_introspection.force_unlock = &mi_force_unlock;

  static malloc_zone_t tcmalloc_zone;
  memset(&tcmalloc_zone, 0, sizeof(malloc_zone_t));

  // Start with a version 4 zone which is used for OS X 10.4 and 10.5.
  tcmalloc_zone.version = 4;
  tcmalloc_zone.zone_name = "tcmalloc";
  tcmalloc_zone.size = &mz_size;
  tcmalloc_zone.malloc = &mz_malloc;
  tcmalloc_zone.calloc = &mz_calloc;
  tcmalloc_zone.valloc = &mz_valloc;
  tcmalloc_zone.free = &mz_free;
  tcmalloc_zone.realloc = &mz_realloc;
  tcmalloc_zone.destroy = &mz_destroy;
  tcmalloc_zone.batch_malloc = nullptr;
  tcmalloc_zone.batch_free = nullptr;
  tcmalloc_zone.introspect = &tcmalloc_introspection;

  // from AvailabilityMacros.h
#if defined(MAC_OS_X_VERSION_10_6) && \
    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  // Switch to version 6 on OSX 10.6 to support memalign.
  tcmalloc_zone.version = 6;
  tcmalloc_zone.memalign = &mz_memalign;
#ifndef __POWERPC__
  tcmalloc_zone.free_definite_size = &mz_free_definite_size;
  tcmalloc_introspection.zone_locked = &mi_zone_locked;
#endif

  // Request the default purgable zone to force its creation. The
  // current default zone is registered with the purgable zone for
  // doing tiny and small allocs.  Sadly, it assumes that the default
  // zone is the szone implementation from OS X and will crash if it
  // isn't.  By creating the zone now, this will be true and changing
  // the default zone won't cause a problem.  This only needs to
  // happen when actually running on OS X 10.6 and higher (note the
  // ifdef above only checks if we were *compiled* with 10.6 or
  // higher; at runtime we have to check if this symbol is defined.)
  if (malloc_default_purgeable_zone) {
    malloc_default_purgeable_zone();
  }
#endif

  // Register the tcmalloc zone. At this point, it will not be the
  // default zone.
  malloc_zone_register(&tcmalloc_zone);

  // Unregister and reregister the default zone.  Unregistering swaps
  // the specified zone with the last one registered which for the
  // default zone makes the more recently registered zone the default
  // zone.  The default zone is then re-registered to ensure that
  // allocations made from it earlier will be handled correctly.
  // Things are not guaranteed to work that way, but it's how they work now.
  malloc_zone_t *default_zone = get_default_zone();
  malloc_zone_unregister(default_zone);
  malloc_zone_register(default_zone);
}

ATTRIBUTE_NOINLINE void* operator new(std::size_t sz) { return tc_new(sz); }
ATTRIBUTE_NOINLINE void* operator new[](std::size_t sz) { return tc_newarray(sz); }
ATTRIBUTE_NOINLINE void operator delete(void* p) { tc_delete(p); }
ATTRIBUTE_NOINLINE void operator delete[](void* p) { tc_deletearray(p); }

ATTRIBUTE_NOINLINE void operator delete(void* p, std::size_t sz) { tc_delete_sized(p, sz); }
ATTRIBUTE_NOINLINE void operator delete[](void* p, std::size_t sz) { tc_deletearray_sized(p, sz); }

ATTRIBUTE_NOINLINE void* operator new(std::size_t sz, const std::nothrow_t& nt) { return tc_new_nothrow(sz, nt); }
ATTRIBUTE_NOINLINE void* operator new[](std::size_t sz, const std::nothrow_t& nt) { return tc_newarray_nothrow(sz, nt); };

ATTRIBUTE_NOINLINE void operator delete(void* p, const std::nothrow_t& nt) { tc_delete_nothrow(p, nt); }
ATTRIBUTE_NOINLINE void operator delete[](void* p, const std::nothrow_t& nt) { tc_deletearray_nothrow(p, nt); }

#if __cplusplus >= 201703L

ATTRIBUTE_NOINLINE void* operator new(std::size_t sz, std::align_val_t a) { return tc_new_aligned(sz, a); }
ATTRIBUTE_NOINLINE void* operator new(std::size_t sz, std::align_val_t al, const std::nothrow_t& nt) { return tc_new_aligned_nothrow(sz, al, nt); }

ATTRIBUTE_NOINLINE void operator delete(void* p, std::align_val_t al) { tc_delete_aligned(p, al); }
ATTRIBUTE_NOINLINE void operator delete(void* p, std::align_val_t al, const std::nothrow_t& nt)  { tc_delete_aligned_nothrow(p, al, nt); }

ATTRIBUTE_NOINLINE void* operator new[](std::size_t sz, std::align_val_t al) { return tc_newarray_aligned(sz, al); }
ATTRIBUTE_NOINLINE void* operator new[](std::size_t sz, std::align_val_t al, const std::nothrow_t& nt) { return tc_newarray_aligned_nothrow(sz, al, nt); }

ATTRIBUTE_NOINLINE void operator delete[](void* p, std::align_val_t al) { tc_deletearray_aligned(p, al); }
ATTRIBUTE_NOINLINE void operator delete[](void* p, std::align_val_t al, const std::nothrow_t& nt) { tc_deletearray_aligned_nothrow(p, al, nt); }

ATTRIBUTE_NOINLINE void operator delete(void* p, std::size_t sz, std::align_val_t al) { tc_delete_sized_aligned(p, sz, al); }
ATTRIBUTE_NOINLINE void operator delete[](void* p, std::size_t sz, std::align_val_t al) { tc_deletearray_sized_aligned(p, sz, al); }

#endif // c++ 17

#endif  // TCMALLOC_LIBC_OVERRIDE_OSX_INL_H_
gperftools-gperftools-2.18/src/libc_override_redefine.h000066400000000000000000000142111513545575200234360ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein 
//
// Used on systems that don't have their own definition of
// malloc/new/etc.  (Typically this will be a windows msvcrt.dll that
// has been edited to remove the definitions.)  We can just define our
// own as normal functions.
//
// This should also work on systems were all the malloc routines are
// defined as weak symbols, and there's no support for aliasing.

#ifndef TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_
#define TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_

#include 

void* operator new(size_t size)                  { return tc_new(size);       }
void operator delete(void* p) CPP_NOTHROW        { tc_delete(p);              }
void* operator new[](size_t size)                { return tc_newarray(size);  }
void operator delete[](void* p) CPP_NOTHROW      { tc_deletearray(p);         }
void* operator new(size_t size, const std::nothrow_t& nt) CPP_NOTHROW {
  return tc_new_nothrow(size, nt);
}
void* operator new[](size_t size, const std::nothrow_t& nt) CPP_NOTHROW {
  return tc_newarray_nothrow(size, nt);
}
void operator delete(void* ptr, const std::nothrow_t& nt) CPP_NOTHROW {
  return tc_delete_nothrow(ptr, nt);
}
void operator delete[](void* ptr, const std::nothrow_t& nt) CPP_NOTHROW {
  return tc_deletearray_nothrow(ptr, nt);
}

#ifdef ENABLE_SIZED_DELETE
void operator delete(void* p, size_t s) CPP_NOTHROW  { tc_delete_sized(p, s);     }
void operator delete[](void* p, size_t s) CPP_NOTHROW{ tc_deletearray_sized(p, s);}
#endif

void* operator new(size_t size, std::align_val_t al) {
  return tc_new_aligned(size, al);
}
void operator delete(void* p, std::align_val_t al) CPP_NOTHROW {
  tc_delete_aligned(p, al);
}
void* operator new[](size_t size, std::align_val_t al) {
  return tc_newarray_aligned(size, al);
}
void operator delete[](void* p, std::align_val_t al) CPP_NOTHROW {
  tc_deletearray_aligned(p, al);
}
void* operator new(size_t size, std::align_val_t al, const std::nothrow_t& nt) CPP_NOTHROW {
  return tc_new_aligned_nothrow(size, al, nt);
}
void* operator new[](size_t size, std::align_val_t al, const std::nothrow_t& nt) CPP_NOTHROW {
  return tc_newarray_aligned_nothrow(size, al, nt);
}
void operator delete(void* ptr, std::align_val_t al, const std::nothrow_t& nt) CPP_NOTHROW {
  return tc_delete_aligned_nothrow(ptr, al, nt);
}
void operator delete[](void* ptr, std::align_val_t al, const std::nothrow_t& nt) CPP_NOTHROW {
  return tc_deletearray_aligned_nothrow(ptr, al, nt);
}

#ifdef ENABLE_SIZED_DELETE
void operator delete(void* p, size_t s, std::align_val_t al) CPP_NOTHROW {
  tc_delete_sized_aligned(p, s, al);
}
void operator delete[](void* p, size_t s, std::align_val_t al) CPP_NOTHROW {
  tc_deletearray_sized_aligned(p, s, al);
}
#endif

#ifndef TCMALLOC_OVERRIDE_ONLY_CXX

extern "C" {
  void* malloc(size_t s)                         { return tc_malloc(s);       }
  void  free(void* p)                            { tc_free(p);                }
  void* realloc(void* p, size_t s)               { return tc_realloc(p, s);   }
  void* calloc(size_t n, size_t s)               { return tc_calloc(n, s);    }
  void  cfree(void* p)                           { tc_cfree(p);               }
  void* memalign(size_t a, size_t s)             { return tc_memalign(a, s);  }
  void* aligned_alloc(size_t a, size_t s)        { return tc_memalign(a, s);  }
  void* valloc(size_t s)                         { return tc_valloc(s);       }
  void* pvalloc(size_t s)                        { return tc_pvalloc(s);      }
  int posix_memalign(void** r, size_t a, size_t s)         {
    return tc_posix_memalign(r, a, s);
  }
  void malloc_stats(void)                        { tc_malloc_stats();         }
  int mallopt(int cmd, int v)                    { return tc_mallopt(cmd, v); }
#ifdef HAVE_STRUCT_MALLINFO
  struct mallinfo mallinfo(void)                 { return tc_mallinfo();      }
#endif
#ifdef HAVE_STRUCT_MALLINFO2
  struct mallinfo2 mallinfo2(void)               { return tc_mallinfo2();     }
#endif
  size_t malloc_size(void* p)                    { return tc_malloc_size(p); }
  size_t malloc_usable_size(void* p)             { return tc_malloc_size(p); }

  // C23
  void free_sized(void* p, size_t size)          { return tc_free_sized(p, size); }
  void free_aligned_sized(void* p, size_t align, size_t size) {return tc_free_aligned_sized(p, align, size); }
}  // extern "C"

#endif // !TCMALOC_OVERRIDE_ONLY_CXX

// No need to do anything at tcmalloc-registration time: we do it all
// via overriding weak symbols (at link time).
static void ReplaceSystemAlloc() { }

#endif  // TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_
gperftools-gperftools-2.18/src/linked_list.h000066400000000000000000000065121513545575200212730ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 
//
// Some very basic linked list functions for dealing with using void * as
// storage.

#ifndef TCMALLOC_LINKED_LIST_H_
#define TCMALLOC_LINKED_LIST_H_

#include 

namespace tcmalloc {

inline void *SLL_Next(void *t) {
  return *(reinterpret_cast(t));
}

inline void SLL_SetNext(void *t, void *n) {
  *(reinterpret_cast(t)) = n;
}

inline void SLL_Push(void **list, void *element) {
  void *next = *list;
  *list = element;
  SLL_SetNext(element, next);
}

inline void *SLL_Pop(void **list) {
  void *result = *list;
  *list = SLL_Next(*list);
  return result;
}

inline bool SLL_TryPop(void **list, void **rv) {
  void *result = *list;
  if (!result) {
    return false;
  }
  void *next = SLL_Next(*list);
  *list = next;
  *rv = result;
  return true;
}

// Remove N elements from a linked list to which head points.  head will be
// modified to point to the new head.  start and end will point to the first
// and last nodes of the range.  Note that end will point to nullptr after this
// function is called.
inline void SLL_PopRange(void **head, int N, void **start, void **end) {
  if (N == 0) {
    *start = nullptr;
    *end = nullptr;
    return;
  }

  void *tmp = *head;
  for (int i = 1; i < N; ++i) {
    tmp = SLL_Next(tmp);
  }

  *start = *head;
  *end = tmp;
  *head = SLL_Next(tmp);
  // Unlink range from list.
  SLL_SetNext(tmp, nullptr);
}

inline void SLL_PushRange(void **head, void *start, void *end) {
  if (!start) return;
  SLL_SetNext(end, *head);
  *head = start;
}

inline size_t SLL_Size(void *head) {
  int count = 0;
  while (head) {
    count++;
    head = SLL_Next(head);
  }
  return count;
}

}  // namespace tcmalloc

#endif  // TCMALLOC_LINKED_LIST_H_
gperftools-gperftools-2.18/src/malloc_backtrace.cc000066400000000000000000000062201513545575200223720ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config.h"

#define THIS_IS_MALLOC_BACKTRACE_CC
#include "malloc_backtrace.h"

#include "thread_cache_ptr.h"

extern "C" {
  void* tc_new(size_t);
  void tc_delete(void*);
}

namespace tcmalloc {

// GrabBacktrace is the API to use when capturing backtrace for
// various tcmalloc features. It has optional emergency malloc
// integration for occasional case where stacktrace capturing method
// calls back to malloc (so we divert those calls to emergency malloc
// facility).
ATTRIBUTE_VISIBILITY_HIDDEN ATTRIBUTE_NOINLINE
int GrabBacktrace(void** result, int max_depth, int skip_count) {
  struct Args {
    void** result;
    int max_depth;
    int skip_count;
    int result_depth;
  } args;

  args.result = result;
  args.max_depth = max_depth;
  args.skip_count = skip_count;
  args.result_depth = 0;

  struct Body {
    static ATTRIBUTE_NOINLINE
    void Run(bool stacktrace_allowed, void* _args) {
      Args* args = static_cast(_args);
      if (!stacktrace_allowed) {
        return;
      }

#if (!defined(NDEBUG) || defined(TCMALLOC_FORCE_BAD_TLS)) && defined(ENABLE_EMERGENCY_MALLOC)
      // Lets ensure test coverage of emergency malloc even in
      // configurations that otherwise don't exercise it.
      (tc_delete)(tc_new(32));
#endif

      args->result_depth = GetStackTrace(args->result, args->max_depth, args->skip_count + 3);
    }
  };

  ThreadCachePtr::WithStacktraceScope(Body::Run, &args);

  // Prevent tail calling WithStacktraceScope above
  return *const_cast(&args.result_depth);
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/malloc_backtrace.h000066400000000000000000000052121513545575200222340ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2014, 2024, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef MALLOC_BACKTRACE_H
#define MALLOC_BACKTRACE_H

#include "config.h"

#include "gperftools/stacktrace.h" // IWYU pragma: keep

namespace tcmalloc {

#ifdef NO_TCMALLOC_SAMPLES

inline int GrabBacktrace(void** result, int max_depth, int skip_count) { return 0; }

inline void MallocBacktraceInit() {}

#else

// GrabBacktrace is the API to use when capturing backtrace for
// various tcmalloc features. It has optional emergency malloc
// integration for occasional case where stacktrace capturing method
// calls back to malloc (so we divert those calls to emergency malloc
// facility).
int GrabBacktrace(void** result, int max_depth, int skip_count);

#endif

}  // namespace tcmalloc

#ifndef THIS_IS_MALLOC_BACKTRACE_CC
// When something includes this file, don't let us use 'regular'
// stacktrace API directly.
#define GetStackTrace(...) missing
#define GetStackTraceWithContext(...) missing
#define GetStackFrames(...) missing
#define GetStackFramesWithContext(...) missing
#endif // THIS_IS_MALLOC_BACKTRACE_CC

#endif  // MALLOC_BACKTRACE_H
gperftools-gperftools-2.18/src/malloc_extension.cc000066400000000000000000000245031513545575200224730ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#include 

#include "gperftools/malloc_extension.h"
#include "gperftools/malloc_extension_c.h"

#include 
#include 
#include 
#include 
#include 

#include 

#include "base/proc_maps_iterator.h"
#include "tcmalloc_internal.h"


#include "thread_cache.h"

static void DumpAddressMap(std::string* result) {
  tcmalloc::StringGenericWriter writer(result);
  writer.AppendStr("\nMAPPED_LIBRARIES:\n");
  tcmalloc::SaveProcSelfMaps(&writer);
}

void MallocExtension::Initialize() {}

// SysAllocator implementation
SysAllocator::~SysAllocator() {}

// Default implementation -- does nothing
MallocExtension::~MallocExtension() { }
bool MallocExtension::VerifyAllMemory() { return true; }
bool MallocExtension::VerifyNewMemory(const void* p) { return true; }
bool MallocExtension::VerifyArrayNewMemory(const void* p) { return true; }
bool MallocExtension::VerifyMallocMemory(const void* p) { return true; }

bool MallocExtension::GetNumericProperty(const char* property, size_t* value) {
  return false;
}

bool MallocExtension::SetNumericProperty(const char* property, size_t value) {
  return false;
}

void MallocExtension::GetStats(char* buffer, int length) {
  assert(length > 0);
  buffer[0] = '\0';
}

bool MallocExtension::MallocMemoryStats(int* blocks, size_t* total,
                                       int histogram[kMallocHistogramSize]) {
  *blocks = 0;
  *total = 0;
  memset(histogram, 0, sizeof(*histogram) * kMallocHistogramSize);
  return true;
}

void** MallocExtension::ReadStackTraces(int* sample_period) {
  return nullptr;
}

void** MallocExtension::ReadHeapGrowthStackTraces() {
  return nullptr;
}

void MallocExtension::MarkThreadIdle() {
  // Default implementation does nothing
}

void MallocExtension::MarkThreadBusy() {
  // Default implementation does nothing
}

SysAllocator* MallocExtension::GetSystemAllocator() {
  return nullptr;
}

void MallocExtension::SetSystemAllocator(SysAllocator *a) {
  // Default implementation does nothing
}

void MallocExtension::ReleaseToSystem(size_t num_bytes) {
  // Default implementation does nothing
}

void MallocExtension::ReleaseFreeMemory() {
  ReleaseToSystem(static_cast(-1));   // SIZE_T_MAX
}

void MallocExtension::SetMemoryReleaseRate(double rate) {
  // Default implementation does nothing
}

double MallocExtension::GetMemoryReleaseRate() {
  return -1.0;
}

size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) {
  return size;
}

size_t MallocExtension::GetAllocatedSize(const void* p) {
  assert(GetOwnership(p) != kNotOwned);
  return 0;
}

MallocExtension::Ownership MallocExtension::GetOwnership(const void* p) {
  return kUnknownOwnership;
}

void MallocExtension::GetFreeListSizes(
  std::vector* v) {
  v->clear();
}

size_t MallocExtension::GetThreadCacheSize() {
  return 0;
}

void MallocExtension::MarkThreadTemporarilyIdle() {
  // Default implementation does nothing
}

// The current malloc extension object.

static std::atomic current_instance;

MallocExtension* MallocExtension::instance() {
  MallocExtension* inst = current_instance.load(std::memory_order_relaxed);
  if (PREDICT_TRUE(inst != nullptr)) {
    return inst;
  }

  // if MallocExtension isn't set up yet, it could be we're called
  // super-early. Trigger tcmalloc initialization and assume it will
  // set up instance().
  tcmalloc::ThreadCache::EnsureMallocInitialized();

  return instance();
}

void MallocExtension::Register(MallocExtension* implementation) {
  current_instance.store(implementation);
}

// -----------------------------------------------------------------------
// Heap sampling support
// -----------------------------------------------------------------------

namespace {

// Accessors
uintptr_t Count(void** entry) {
  return reinterpret_cast(entry[0]);
}
uintptr_t Size(void** entry) {
  return reinterpret_cast(entry[1]);
}
uintptr_t Depth(void** entry) {
  return reinterpret_cast(entry[2]);
}
void* PC(void** entry, int i) {
  return entry[3+i];
}

void PrintCountAndSize(MallocExtensionWriter* writer,
                       uintptr_t count, uintptr_t size) {
  char buf[100];
  snprintf(buf, sizeof(buf),
           "%6" PRIu64 ": %8" PRIu64 " [%6" PRIu64 ": %8" PRIu64 "] @",
           static_cast(count),
           static_cast(size),
           static_cast(count),
           static_cast(size));
  writer->append(buf, strlen(buf));
}

void PrintHeader(MallocExtensionWriter* writer,
                 const char* label, void** entries) {
  // Compute the total count and total size
  uintptr_t total_count = 0;
  uintptr_t total_size = 0;
  for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
    total_count += Count(entry);
    total_size += Size(entry);
  }

  const char* const kTitle = "heap profile: ";
  writer->append(kTitle, strlen(kTitle));
  PrintCountAndSize(writer, total_count, total_size);
  writer->append(" ", 1);
  writer->append(label, strlen(label));
  writer->append("\n", 1);
}

void PrintStackEntry(MallocExtensionWriter* writer, void** entry) {
  PrintCountAndSize(writer, Count(entry), Size(entry));

  for (int i = 0; i < Depth(entry); i++) {
    char buf[32];
    snprintf(buf, sizeof(buf), " %p", PC(entry, i));
    writer->append(buf, strlen(buf));
  }
  writer->append("\n", 1);
}

}

void MallocExtension::GetHeapSample(MallocExtensionWriter* writer) {
  int sample_period = 0;
  void** entries = ReadStackTraces(&sample_period);
  if (entries == nullptr) {
    const char* const kErrorMsg =
        "This malloc implementation does not support sampling.\n"
        "As of 2005/01/26, only tcmalloc supports sampling, and\n"
        "you are probably running a binary that does not use\n"
        "tcmalloc.\n";
    writer->append(kErrorMsg, strlen(kErrorMsg));
    return;
  }

  char label[32];
  snprintf(label, sizeof(label), "heap_v2/%d", sample_period);
  PrintHeader(writer, label, entries);
  for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
    PrintStackEntry(writer, entry);
  }
  delete[] entries;

  DumpAddressMap(writer);
}

void MallocExtension::GetHeapGrowthStacks(MallocExtensionWriter* writer) {
  void** entries = ReadHeapGrowthStackTraces();
  if (entries == nullptr) {
    const char* const kErrorMsg =
        "This malloc implementation does not support "
        "ReadHeapGrowthStackTraces().\n"
        "As of 2005/09/27, only tcmalloc supports this, and you\n"
        "are probably running a binary that does not use tcmalloc.\n";
    writer->append(kErrorMsg, strlen(kErrorMsg));
    return;
  }

  // Do not canonicalize the stack entries, so that we get a
  // time-ordered list of stack traces, which may be useful if the
  // client wants to focus on the latest stack traces.
  PrintHeader(writer, "growth", entries);
  for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
    PrintStackEntry(writer, entry);
  }
  delete[] entries;

  DumpAddressMap(writer);
}

void MallocExtension::Ranges(void* arg, RangeFunction func) {
  // No callbacks by default
}

// These are C shims that work on the current instance.

#define C_SHIM(fn, retval, paramlist, arglist)          \
  extern "C" PERFTOOLS_DLL_DECL retval MallocExtension_##fn paramlist {    \
    return MallocExtension::instance()->fn arglist;     \
  }

C_SHIM(VerifyAllMemory, int, (void), ());
C_SHIM(VerifyNewMemory, int, (const void* p), (p));
C_SHIM(VerifyArrayNewMemory, int, (const void* p), (p));
C_SHIM(VerifyMallocMemory, int, (const void* p), (p));
C_SHIM(MallocMemoryStats, int,
       (int* blocks, size_t* total, int histogram[kMallocHistogramSize]),
       (blocks, total, histogram));

C_SHIM(GetStats, void,
       (char* buffer, int buffer_length), (buffer, buffer_length));
C_SHIM(GetNumericProperty, int,
       (const char* property, size_t* value), (property, value));
C_SHIM(SetNumericProperty, int,
       (const char* property, size_t value), (property, value));

C_SHIM(MarkThreadIdle, void, (void), ());
C_SHIM(MarkThreadBusy, void, (void), ());
C_SHIM(ReleaseFreeMemory, void, (void), ());
C_SHIM(ReleaseToSystem, void, (size_t num_bytes), (num_bytes));
C_SHIM(SetMemoryReleaseRate, void, (double rate), (rate));
C_SHIM(GetMemoryReleaseRate, double, (void), ());
C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size));
C_SHIM(GetAllocatedSize, size_t, (const void* p), (p));
C_SHIM(GetThreadCacheSize, size_t, (void), ());
C_SHIM(MarkThreadTemporarilyIdle, void, (void), ());

// Can't use the shim here because of the need to translate the enums.
extern "C"
MallocExtension_Ownership MallocExtension_GetOwnership(const void* p) {
  return static_cast(
      MallocExtension::instance()->GetOwnership(p));
}
gperftools-gperftools-2.18/src/malloc_hook-inl.h000066400000000000000000000126711513545575200220440ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// This has the implementation details of malloc_hook that are needed
// to use malloc-hook inside the tcmalloc system.  It does not hold
// any of the client-facing calls that are used to add new hooks.

#ifndef _MALLOC_HOOK_INL_H_
#define _MALLOC_HOOK_INL_H_

#include 
#include 

#include 

#include "base/basictypes.h"
#include 

namespace base { namespace internal {

// Capacity of 8 means that HookList is 9 words.
static const int kHookListCapacity = 8;
// last entry is reserved for deprecated "singular" hooks. So we have
// 7 "normal" hooks per list
static const int kHookListMaxValues = 7;
static const int kHookListSingularIdx = 7;

// HookList: a class that provides synchronized insertions and removals and
// lockless traversal.  Most of the implementation is in malloc_hook.cc.
template 
struct HookList {
  static_assert(sizeof(T) <= sizeof(uintptr_t), "must fit in uintptr_t");

  constexpr HookList() = default;
  explicit constexpr HookList(T priv_data_initial) : priv_end{1}, priv_data{priv_data_initial} {}

  // Adds value to the list.  Note that duplicates are allowed.  Thread-safe and
  // blocking (acquires hooklist_spinlock).  Returns true on success; false
  // otherwise (failures include invalid value and no space left).
  bool Add(T value);

  void FixupPrivEndLocked();

  // Removes the first entry matching value from the list.  Thread-safe and
  // blocking (acquires hooklist_spinlock).  Returns true on success; false
  // otherwise (failures include invalid value and no value found).
  bool Remove(T value);

  // Store up to n values of the list in output_array, and return the number of
  // elements stored.  Thread-safe and non-blocking.  This is fast (one memory
  // access) if the list is empty.
  int Traverse(T* output_array, int n) const;

  // Fast inline implementation for fast path of Invoke*Hook.
  bool empty() const {
    return priv_end.load(std::memory_order_relaxed) == 0;
  }

  // Used purely to handle deprecated singular hooks
  T GetSingular() const {
    return bit_cast(cast_priv_data(kHookListSingularIdx)->load(std::memory_order_relaxed));
  }

  T ExchangeSingular(T new_val);

  // This internal data is not private so that the class is an aggregate and can
  // be initialized by the linker.  Don't access this directly.  Use the
  // INIT_HOOK_LIST macro in malloc_hook.cc.

  // One more than the index of the last valid element in priv_data.  During
  // 'Remove' this may be past the last valid element in priv_data, but
  // subsequent values will be 0.
  //
  // Index kHookListCapacity-1 is reserved as 'deprecated' single hook pointer
  std::atomic priv_end;
  T priv_data[kHookListCapacity];

  // C++ 11 doesn't let us initialize array of atomics, so we made
  // priv_data regular array of T and cast when reading and writing
  // (which is portable in practice)
  std::atomic* cast_priv_data(int index) {
    return reinterpret_cast*>(priv_data + index);
  }
  std::atomic const * cast_priv_data(int index) const {
    return reinterpret_cast const *>(priv_data + index);
  }
};

ATTRIBUTE_VISIBILITY_HIDDEN extern HookList new_hooks_;
ATTRIBUTE_VISIBILITY_HIDDEN extern HookList delete_hooks_;

} }  // namespace base::internal

// The following method is DEPRECATED

namespace tcmalloc {
void InvokeNewHookSlow(const void* p, size_t s);
void InvokeDeleteHookSlow(const void* p);

static inline void InvokeNewHook(const void* p, size_t s) {
  if (PREDICT_FALSE(!base::internal::new_hooks_.empty())) {
    InvokeNewHookSlow(p, s);
  }
}

static inline void InvokeDeleteHook(const void* p) {
  if (PREDICT_FALSE(!base::internal::delete_hooks_.empty())) {
    InvokeDeleteHookSlow(p);
  }
}

}  // namespace tcmalloc

#endif /* _MALLOC_HOOK_INL_H_ */
gperftools-gperftools-2.18/src/malloc_hook.cc000066400000000000000000000246631513545575200214260ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#include 

#include 
#include "malloc_hook-inl.h"

#include 
#include 
#if HAVE_SYS_SYSCALL_H
#include 
#endif

#ifdef HAVE_MMAP
#include 
#endif

#include "base/logging.h"
#include "base/spinlock.h"
#include "malloc_backtrace.h"
#include "maybe_emergency_malloc.h" // IWYU pragma: keep

// __THROW is defined in glibc systems.  It means, counter-intuitively,
// "This function will never throw an exception."  It's an optional
// optimization tool, but we may need to use it to match glibc prototypes.
#ifndef __THROW    // I guess we're not on a glibc system
# define __THROW   // __THROW is just an optimization, so ok to make it ""
#endif

namespace base { namespace internal {

// This lock is shared between all implementations of HookList::Add & Remove.
// The potential for contention is very small.  This needs to be a SpinLock and
// not a Mutex since it's possible for Mutex locking to allocate memory (e.g.,
// per-thread allocation in debug builds), which could cause infinite recursion.
static SpinLock hooklist_spinlock;

template 
bool HookList::Add(T value) {
  if (value == T{}) {
    return false;
  }
  SpinLockHolder l(&hooklist_spinlock);
  // Find the first slot in data that is 0.
  int index = 0;
  while ((index < kHookListMaxValues) &&
         cast_priv_data(index)->load(std::memory_order_relaxed) != T{}) {
    ++index;
  }
  if (index == kHookListMaxValues) {
    return false;
  }
  uintptr_t prev_num_hooks = priv_end.load(std::memory_order_acquire);
  cast_priv_data(index)->store(value, std::memory_order_relaxed);
  if (prev_num_hooks <= index) {
    priv_end.store(index + 1, std::memory_order_relaxed);
  }
  return true;
}

template 
void HookList::FixupPrivEndLocked() {
  uintptr_t hooks_end = priv_end.load(std::memory_order_relaxed);
  while ((hooks_end > 0) &&
         cast_priv_data(hooks_end-1)->load(std::memory_order_relaxed) == 0) {
    --hooks_end;
  }
  priv_end.store(hooks_end, std::memory_order_relaxed);
}

template 
bool HookList::Remove(T value) {
  if (value == T{}) {
    return false;
  }
  SpinLockHolder l(&hooklist_spinlock);
  uintptr_t hooks_end = priv_end.load(std::memory_order_relaxed);
  int index = 0;
  while (index < hooks_end
         && value != cast_priv_data(index)->load(std::memory_order_relaxed)) {
    ++index;
  }
  if (index == hooks_end) {
    return false;
  }
  cast_priv_data(index)->store(T{}, std::memory_order_relaxed);
  FixupPrivEndLocked();
  return true;
}

template 
int HookList::Traverse(T* output_array, int n) const {
  uintptr_t hooks_end = priv_end.load(std::memory_order_acquire);
  int actual_hooks_end = 0;
  for (int i = 0; i < hooks_end && n > 0; ++i) {
    T data = cast_priv_data(i)->load(std::memory_order_acquire);
    if (data != T{}) {
      *output_array++ = data;
      ++actual_hooks_end;
      --n;
    }
  }
  return actual_hooks_end;
}

template 
T HookList::ExchangeSingular(T value) {
  T old_value;
  SpinLockHolder l(&hooklist_spinlock);
  old_value = cast_priv_data(kHookListSingularIdx)->load(std::memory_order_relaxed);
  cast_priv_data(kHookListSingularIdx)->store(value, std::memory_order_relaxed);
  if (value != T{}) {
    priv_end.store(kHookListSingularIdx + 1, std::memory_order_relaxed);
  } else {
    FixupPrivEndLocked();
  }
  return old_value;
}

// Explicit instantiation for malloc_hook_test.cc.  This ensures all the methods
// are instantiated.
template struct HookList;

HookList new_hooks_;
HookList delete_hooks_;

} }  // namespace base::internal

using base::internal::kHookListMaxValues;
using base::internal::new_hooks_;
using base::internal::delete_hooks_;

// These are available as C bindings as well as C++, hence their
// definition outside the MallocHook class.
extern "C"
int MallocHook_AddNewHook(MallocHook_NewHook hook) {
  RAW_VLOG(10, "AddNewHook(%p)", hook);
  return new_hooks_.Add(hook);
}

extern "C"
int MallocHook_RemoveNewHook(MallocHook_NewHook hook) {
  RAW_VLOG(10, "RemoveNewHook(%p)", hook);
  return new_hooks_.Remove(hook);
}

extern "C"
int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook) {
  RAW_VLOG(10, "AddDeleteHook(%p)", hook);
  return delete_hooks_.Add(hook);
}

extern "C"
int MallocHook_RemoveDeleteHook(MallocHook_DeleteHook hook) {
  RAW_VLOG(10, "RemoveDeleteHook(%p)", hook);
  return delete_hooks_.Remove(hook);
}

// Next are "legacy" singular new/delete hooks

// The code below is DEPRECATED.
extern "C"
MallocHook_NewHook MallocHook_SetNewHook(MallocHook_NewHook hook) {
  RAW_VLOG(10, "SetNewHook(%p)", hook);
  return new_hooks_.ExchangeSingular(hook);
}

extern "C"
MallocHook_DeleteHook MallocHook_SetDeleteHook(MallocHook_DeleteHook hook) {
  RAW_VLOG(10, "SetDeleteHook(%p)", hook);
  return delete_hooks_.ExchangeSingular(hook);
}

namespace tcmalloc {

void InvokeNewHookSlow(const void* p, size_t s) {
  if (IsEmergencyPtr(p)) {
    return;
  }
  MallocHook::NewHook hooks[kHookListMaxValues];
  int num_hooks = base::internal::new_hooks_.Traverse(hooks, kHookListMaxValues);
  for (int i = 0; i < num_hooks; i++) {
    hooks[i](p, s);
  }
}

void InvokeDeleteHookSlow(const void* p) {
  if (IsEmergencyPtr(p)) {
    return;
  }
  MallocHook::DeleteHook hooks[kHookListMaxValues];
  int num_hooks = base::internal::delete_hooks_.Traverse(hooks, kHookListMaxValues);
  for (int i = 0; i < num_hooks; i++) {
    hooks[i](p);
  }
}

}  // namespace tcmalloc

// We can improve behavior/compactness of this function
// if we pass a generic test function (with a generic arg)
// into the implementations for GetStackTrace instead of the skip_count.
extern "C" int MallocHook_GetCallerStackTrace(void** result, int max_depth,
                                              int skip_count) {
#if defined(NO_TCMALLOC_SAMPLES)
  return 0;
#else
  if (max_depth < 1) {
    return 0;
  }
  // Fall back to GetStackTrace and good old but fragile frame skip counts.
  // Note: this path is inaccurate when a hook is not called directly by an
  // allocation function but is daisy-chained through another hook,
  // search for MallocHook::(Get|Set|Invoke)* to find such cases.
  int retval = tcmalloc::GrabBacktrace(result, max_depth, skip_count);
  // prevent tail-call above
  *(void* volatile *)result;
  return retval;
#endif
}

// All mmap hooks functions are empty and bogus. All of those below
// are no op and we keep them only because we have them exposed in
// headers we ship. So keep them for somewhat formal ABI compat.
//
extern "C"
int MallocHook_AddPreMmapHook(MallocHook_PreMmapHook hook) {
  return 0;
}

extern "C"
int MallocHook_RemovePreMmapHook(MallocHook_PreMmapHook hook) {
  return 0;
}

extern "C"
int MallocHook_SetMmapReplacement(MallocHook_MmapReplacement hook) {
  return 0;
}

extern "C"
int MallocHook_RemoveMmapReplacement(MallocHook_MmapReplacement hook) {
  return 0;
}

extern "C"
int MallocHook_AddMmapHook(MallocHook_MmapHook hook) {
  return 0;
}

extern "C"
int MallocHook_RemoveMmapHook(MallocHook_MmapHook hook) {
  return 0;
}

extern "C"
int MallocHook_AddMunmapHook(MallocHook_MunmapHook hook) {
  return 0;
}

extern "C"
int MallocHook_RemoveMunmapHook(MallocHook_MunmapHook hook) {
  return 0;
}

extern "C"
int MallocHook_SetMunmapReplacement(MallocHook_MunmapReplacement hook) {
  return 0;
}

extern "C"
int MallocHook_RemoveMunmapReplacement(MallocHook_MunmapReplacement hook) {
  return 0;
}

extern "C"
int MallocHook_AddMremapHook(MallocHook_MremapHook hook) {
  return 0;
}

extern "C"
int MallocHook_RemoveMremapHook(MallocHook_MremapHook hook) {
  return 0;
}

extern "C"
int MallocHook_AddPreSbrkHook(MallocHook_PreSbrkHook hook) {
  return 0;
}

extern "C"
int MallocHook_RemovePreSbrkHook(MallocHook_PreSbrkHook hook) {
  return 0;
}

extern "C"
int MallocHook_AddSbrkHook(MallocHook_SbrkHook hook) {
  return 0;
}

extern "C"
int MallocHook_RemoveSbrkHook(MallocHook_SbrkHook hook) {
  return 0;
}

/*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
                                         int flags, int fd, off_t offset) {
  errno = ENOSYS;
  return MAP_FAILED;
}

/*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) {
  errno = ENOSYS;
  return -1;
}

extern "C"
MallocHook_PreMmapHook MallocHook_SetPreMmapHook(MallocHook_PreMmapHook hook) {
  return 0;
}

extern "C"
MallocHook_MmapHook MallocHook_SetMmapHook(MallocHook_MmapHook hook) {
  return 0;
}

extern "C"
MallocHook_MunmapHook MallocHook_SetMunmapHook(MallocHook_MunmapHook hook) {
  return 0;
}

extern "C"
MallocHook_MremapHook MallocHook_SetMremapHook(MallocHook_MremapHook hook) {
  return 0;
}

extern "C"
MallocHook_PreSbrkHook MallocHook_SetPreSbrkHook(MallocHook_PreSbrkHook hook) {
  return 0;
}

extern "C"
MallocHook_SbrkHook MallocHook_SetSbrkHook(MallocHook_SbrkHook hook) {
  return 0;
}

gperftools-gperftools-2.18/src/maybe_emergency_malloc.h000066400000000000000000000044741513545575200234610ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2014, 2024, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef MAYBE_EMERGENCY_MALLOC_H
#define MAYBE_EMERGENCY_MALLOC_H

#include 

#ifdef ENABLE_EMERGENCY_MALLOC

#include "emergency_malloc.h" // IWYU pragma: keep

#else

namespace tcmalloc {

static inline void *EmergencyMalloc(size_t size) {return nullptr;}
static inline void EmergencyFree(void *p) {}
static inline void *EmergencyCalloc(size_t n, size_t elem_size) {return nullptr;}
static inline void *EmergencyRealloc(void *old_ptr, size_t new_size) {return nullptr;}
static inline bool IsEmergencyPtr(const void *_ptr) {return false;}
static inline size_t EmergencyAllocatedSize(const void* p) { return 0; }

}  // namespace tcmalloc

#endif  // ENABLE_EMERGENCY_MALLOC

#endif  // MAYBE_EMERGENCY_MALLOC_H
gperftools-gperftools-2.18/src/memfs_malloc.cc000066400000000000000000000240651513545575200215710ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Arun Sharma
//
// A tcmalloc system allocator that uses a memory based filesystem such as
// tmpfs or hugetlbfs
//
// Since these only exist on linux, we only register this allocator there.

#ifdef __linux

#include 
#include                       // for errno, EINVAL
#include                    // for PRId64
#include                      // for PATH_MAX
#include                      // for size_t
#include                      // for int64_t, uintptr_t
#include                       // for snprintf
#include                      // for mkstemp
#include                      // for strerror
#include                    // for mmap, MAP_FAILED, etc
#include                  // for fstatfs, statfs
#include                      // for ftruncate, off_t, unlink
#include 

#include 
#include "base/googleinit.h"
#include "base/static_storage.h"
#include "internal_logging.h"
#include "safe_strerror.h"

// TODO(sanjay): Move the code below into the tcmalloc namespace
using tcmalloc::kLog;
using tcmalloc::kCrash;
using tcmalloc::Log;

DEFINE_string(memfs_malloc_path, EnvToString("TCMALLOC_MEMFS_MALLOC_PATH", ""),
              "Path where hugetlbfs or tmpfs is mounted. The caller is "
              "responsible for ensuring that the path is unique and does "
              "not conflict with another process");
DEFINE_int64(memfs_malloc_limit_mb,
             EnvToInt("TCMALLOC_MEMFS_LIMIT_MB", 0),
             "Limit total allocation size to the "
             "specified number of MiB.  0 == no limit.");
DEFINE_bool(memfs_malloc_abort_on_fail,
            EnvToBool("TCMALLOC_MEMFS_ABORT_ON_FAIL", false),
            "abort() whenever memfs_malloc fails to satisfy an allocation "
            "for any reason.");
DEFINE_bool(memfs_malloc_ignore_mmap_fail,
            EnvToBool("TCMALLOC_MEMFS_IGNORE_MMAP_FAIL", false),
            "Ignore failures from mmap");
DEFINE_bool(memfs_malloc_map_private,
            EnvToBool("TCMALLOC_MEMFS_MAP_PRIVATE", false),
	    "Use MAP_PRIVATE with mmap");
DEFINE_bool(memfs_malloc_disable_fallback,
            EnvToBool("TCMALLOC_MEMFS_DISABLE_FALLBACK", false),
            "If we run out of hugepage memory don't fallback to default "
            "allocator.");

// Hugetlbfs based allocator for tcmalloc
class HugetlbSysAllocator: public SysAllocator {
public:
  explicit HugetlbSysAllocator(SysAllocator* fallback)
    : failed_(true),  // To disable allocator until Initialize() is called.
      big_page_size_(0),
      hugetlb_fd_(-1),
      hugetlb_base_(0),
      fallback_(fallback) {
  }

  void* Alloc(size_t size, size_t *actual_size, size_t alignment);
  bool Initialize();

  bool failed_;          // Whether failed to allocate memory.

private:
  void* AllocInternal(size_t size, size_t *actual_size, size_t alignment);

  int64_t big_page_size_;
  int hugetlb_fd_;       // file descriptor for hugetlb
  off_t hugetlb_base_;

  SysAllocator* fallback_;  // Default system allocator to fall back to.
};
static tcmalloc::StaticStorage hugetlb_space;

// No locking needed here since we assume that tcmalloc calls
// us with an internal lock held (see tcmalloc/system-alloc.cc).
void* HugetlbSysAllocator::Alloc(size_t size, size_t *actual_size,
                                 size_t alignment) {
  if (!FLAGS_memfs_malloc_disable_fallback && failed_) {
    return fallback_->Alloc(size, actual_size, alignment);
  }

  // We don't respond to allocation requests smaller than big_page_size_ unless
  // the caller is ok to take more than they asked for. Used by MetaDataAlloc.
  if (!FLAGS_memfs_malloc_disable_fallback &&
      actual_size == nullptr && size < big_page_size_) {
    return fallback_->Alloc(size, actual_size, alignment);
  }

  // Enforce huge page alignment.  Be careful to deal with overflow.
  size_t new_alignment = alignment;
  if (new_alignment < big_page_size_) new_alignment = big_page_size_;
  size_t aligned_size = ((size + new_alignment - 1) /
                         new_alignment) * new_alignment;
  if (!FLAGS_memfs_malloc_disable_fallback && aligned_size < size) {
    return fallback_->Alloc(size, actual_size, alignment);
  }

  void* result = AllocInternal(aligned_size, actual_size, new_alignment);
  if (result != nullptr) {
    return result;
  } else if (FLAGS_memfs_malloc_disable_fallback) {
    return nullptr;
  }
  Log(kLog, __FILE__, __LINE__,
      "HugetlbSysAllocator: (failed, allocated)", failed_, hugetlb_base_);
  if (FLAGS_memfs_malloc_abort_on_fail) {
    Log(kCrash, __FILE__, __LINE__,
        "memfs_malloc_abort_on_fail is set");
  }
  return fallback_->Alloc(size, actual_size, alignment);
}

void* HugetlbSysAllocator::AllocInternal(size_t size, size_t* actual_size,
                                         size_t alignment) {
  // Ask for extra memory if alignment > pagesize
  size_t extra = 0;
  if (alignment > big_page_size_) {
    extra = alignment - big_page_size_;
  }

  // Test if this allocation would put us over the limit.
  off_t limit = FLAGS_memfs_malloc_limit_mb*1024*1024;
  if (limit > 0 && hugetlb_base_ + size + extra > limit) {
    // Disable the allocator when there's less than one page left.
    if (limit - hugetlb_base_ < big_page_size_) {
      Log(kLog, __FILE__, __LINE__, "reached memfs_malloc_limit_mb");
      failed_ = true;
    }
    else {
      Log(kLog, __FILE__, __LINE__,
          "alloc too large (size, bytes left)", size, limit-hugetlb_base_);
    }
    return nullptr;
  }

  // This is not needed for hugetlbfs, but needed for tmpfs.  Annoyingly
  // hugetlbfs returns EINVAL for ftruncate.
  int ret = ftruncate(hugetlb_fd_, hugetlb_base_ + size + extra);
  if (ret != 0 && errno != EINVAL) {
    Log(kLog, __FILE__, __LINE__,
        "ftruncate failed", tcmalloc::SafeStrError(errno).c_str());
    failed_ = true;
    return nullptr;
  }

  // Note: size + extra does not overflow since:
  //            size + alignment < (1<(MAP_FAILED)) {
    if (!FLAGS_memfs_malloc_ignore_mmap_fail) {
      Log(kLog, __FILE__, __LINE__,
          "mmap failed (size, error)", size + extra,
          tcmalloc::SafeStrError(errno).c_str());
      failed_ = true;
    }
    return nullptr;
  }
  uintptr_t ptr = reinterpret_cast(result);

  // Adjust the return memory so it is aligned
  size_t adjust = 0;
  if ((ptr & (alignment - 1)) != 0) {
    adjust = alignment - (ptr & (alignment - 1));
  }
  ptr += adjust;
  hugetlb_base_ += (size + extra);

  if (actual_size) {
    *actual_size = size + extra - adjust;
  }

  return reinterpret_cast(ptr);
}

bool HugetlbSysAllocator::Initialize() {
  char path[PATH_MAX];
  const int pathlen = FLAGS_memfs_malloc_path.size();
  if (pathlen + 8 > sizeof(path)) {
    Log(kCrash, __FILE__, __LINE__, "XX fatal: memfs_malloc_path too long");
    return false;
  }
  memcpy(path, FLAGS_memfs_malloc_path.data(), pathlen);
  memcpy(path + pathlen, ".XXXXXX", 8);  // Also copies terminating \0

  int hugetlb_fd = mkstemp(path);
  if (hugetlb_fd == -1) {
    Log(kLog, __FILE__, __LINE__,
        "warning: unable to create memfs_malloc_path",
        path, tcmalloc::SafeStrError(errno).c_str());
    return false;
  }

  // Cleanup memory on process exit
  if (unlink(path) == -1) {
    Log(kCrash, __FILE__, __LINE__,
        "fatal: error unlinking memfs_malloc_path", path,
        tcmalloc::SafeStrError(errno).c_str());
    return false;
  }

  // Use fstatfs to figure out the default page size for memfs
  struct statfs sfs;
  if (fstatfs(hugetlb_fd, &sfs) == -1) {
    Log(kCrash, __FILE__, __LINE__,
        "fatal: error fstatfs of memfs_malloc_path",
        tcmalloc::SafeStrError(errno).c_str());
    return false;
  }
  int64_t page_size = sfs.f_bsize;

  hugetlb_fd_ = hugetlb_fd;
  big_page_size_ = page_size;
  failed_ = false;
  return true;
}

REGISTER_MODULE_INITIALIZER(memfs_malloc, {
  if (FLAGS_memfs_malloc_path.length()) {
    SysAllocator* alloc = MallocExtension::instance()->GetSystemAllocator();
    HugetlbSysAllocator* hp = hugetlb_space.Construct(alloc);
    if (hp->Initialize()) {
      MallocExtension::instance()->SetSystemAllocator(hp);
    }
  }
});

#endif   /* ifdef __linux */
gperftools-gperftools-2.18/src/packed-cache-inl.h000066400000000000000000000210511513545575200220350ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Geoff Pike
//
// This file provides a minimal cache that can hold a  pair
// with little if any wasted space.  The types of the key and value
// must be unsigned integral types or at least have unsigned semantics
// for >>, casting, and similar operations.
//
// Synchronization is not provided.  However, the cache is implemented
// as an array of cache entries whose type is chosen at compile time.
// If a[i] is atomic on your hardware for the chosen array type then
// raciness will not necessarily lead to bugginess.  The cache entries
// must be large enough to hold a partial key and a value packed
// together.  The partial keys are bit strings of length
// kKeybits - kHashbits, and the values are bit strings of length kValuebits.
//
// In an effort to use minimal space, every cache entry represents
// some  pair; the class provides no way to mark a cache
// entry as empty or uninitialized.  In practice, you may want to have
// reserved keys or values to get around this limitation.  For example, in
// tcmalloc's PageID-to-sizeclass cache, a value of 0 is used as
// "unknown sizeclass."
//
// Usage Considerations
// --------------------
//
// kHashbits controls the size of the cache.  The best value for
// kHashbits will of course depend on the application.  Perhaps try
// tuning the value of kHashbits by measuring different values on your
// favorite benchmark.  Also remember not to be a pig; other
// programs that need resources may suffer if you are.
//
// The main uses for this class will be when performance is
// critical and there's a convenient type to hold the cache's
// entries.  As described above, the number of bits required
// for a cache entry is (kKeybits - kHashbits) + kValuebits.  Suppose
// kKeybits + kValuebits is 43.  Then it probably makes sense to
// chose kHashbits >= 11 so that cache entries fit in a uint32.
//
// On the other hand, suppose kKeybits = kValuebits = 64.  Then
// using this class may be less worthwhile.  You'll probably
// be using 128 bits for each entry anyway, so maybe just pick
// a hash function, H, and use an array indexed by H(key):
//    void Put(K key, V value) { a_[H(key)] = pair(key, value); }
//    V GetOrDefault(K key, V default) { const pair &p = a_[H(key)]; ... }
//    etc.
//
// Further Details
// ---------------
//
// For caches used only by one thread, the following is true:
// 1. For a cache c,
//      (c.Put(key, value), c.GetOrDefault(key, 0)) == value
//    and
//      (c.Put(key, value), <...>, c.GetOrDefault(key, 0)) == value
//    if the elided code contains no c.Put calls.
//
// 2. Has(key) will return false if no  pair with that key
//    has ever been Put.  However, a newly initialized cache will have
//    some  pairs already present.  When you create a new
//    cache, you must specify an "initial value."  The initialization
//    procedure is equivalent to Clear(initial_value), which is
//    equivalent to Put(k, initial_value) for all keys k from 0 to
//    2^kHashbits - 1.
//
// 3. If key and key' differ then the only way Put(key, value) may
//    cause Has(key') to change is that Has(key') may change from true to
//    false. Furthermore, a Put() call that doesn't change Has(key')
//    doesn't change GetOrDefault(key', ...) either.
//
// Implementation details:
//
// This is a direct-mapped cache with 2^kHashbits entries; the hash
// function simply takes the low bits of the key.  We store whole keys
// if a whole key plus a whole value fits in an entry.  Otherwise, an
// entry is the high bits of a key and a value, packed together.
// E.g., a 20 bit key and a 7 bit value only require a uint16 for each
// entry if kHashbits >= 11.
//
// Alternatives to this scheme will be added as needed.

#ifndef TCMALLOC_PACKED_CACHE_INL_H_
#define TCMALLOC_PACKED_CACHE_INL_H_

#include "config.h"

#include                      // for size_t
#include                      // for uintptr_t

#include "base/basictypes.h"
#include "internal_logging.h"

// A safe way of doing "(1 << n) - 1" -- without worrying about overflow
// Note this will all be resolved to a constant expression at compile-time
#define N_ONES_(IntType, N)                                     \
  ( (N) == 0 ? 0 : ((static_cast(1) << ((N)-1))-1 +    \
                    (static_cast(1) << ((N)-1))) )

// The types K and V provide upper bounds on the number of valid keys
// and values, but we explicitly require the keys to be less than
// 2^kKeybits and the values to be less than 2^kValuebits.  The size
// of the table is controlled by kHashbits, and the type of each entry
// in the cache is uintptr_t (native machine word).  See also the big
// comment at the top of the file.
template 
class PackedCache {
 public:
  typedef uintptr_t T;
  typedef uintptr_t K;
  typedef uint32_t V;

#ifdef TCMALLOC_SMALL_BUT_SLOW
  static constexpr int kWantHashBits = 12;
#else // !TCMALLOC_SMALL_BUT_SLOW
  static constexpr int kWantHashBits = 16;
#endif

  static constexpr int kHashbits
    = (kKeybits < kWantHashBits) ? kKeybits : kWantHashBits;

  static constexpr int kValuebits = 7;
  // one bit after value bits
  static constexpr int kInvalidMask = 0x80;

  explicit PackedCache() {
    static_assert(kKeybits + kValuebits + 1 <= 8 * sizeof(T));
    static_assert(kHashbits <= kKeybits);
    static_assert(kHashbits >= kValuebits + 1);
    Clear();
  }

  bool TryGet(K key, V* out) const {
    // As with other code in this class, we touch array_ as few times
    // as we can.  Assuming entries are read atomically then certain
    // races are harmless.
    ASSERT(key == (key & kKeyMask));
    T hash = Hash(key);
    T expected_entry = key;
    expected_entry &= ~N_ONES_(T, kHashbits);
    T entry = array_[hash];
    entry ^= expected_entry;
    if (PREDICT_FALSE(entry >= (1 << kValuebits))) {
      return false;
    }
    *out = static_cast(entry);
    return true;
  }

  void Clear() {
    // sets 'invalid' bit in every byte, include value byte
    memset(const_cast(array_), kInvalidMask, sizeof(array_));
  }

  void Put(K key, V value) {
    ASSERT(key == (key & kKeyMask));
    ASSERT(value == (value & kValueMask));
    array_[Hash(key)] = KeyToUpper(key) | value;
  }

  void Invalidate(K key) {
    ASSERT(key == (key & kKeyMask));
    array_[Hash(key)] = KeyToUpper(key) | kInvalidMask;
  }

 private:
  // we just wipe all hash bits out of key. I.e. clear lower
  // kHashbits. We rely on compiler knowing value of Hash(k).
  static T KeyToUpper(K k) {
    return static_cast(k) ^ Hash(k);
  }

  static T Hash(K key) {
    return static_cast(key) & N_ONES_(size_t, kHashbits);
  }

  // For masking a K.
  static const K kKeyMask = N_ONES_(K, kKeybits);

  // For masking a V or a T.
  static const V kValueMask = N_ONES_(V, kValuebits);

  // array_ is the cache.  Its elements are volatile because any
  // thread can write any array element at any time.
  volatile T array_[1 << kHashbits];
};

#undef N_ONES_

#endif  // TCMALLOC_PACKED_CACHE_INL_H_
gperftools-gperftools-2.18/src/page_heap.cc000066400000000000000000000663751513545575200210560ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#include "config.h"

#include                    // for PRIuPTR
#include                       // for ENOMEM, errno

#include 

#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "gperftools/malloc_extension.h"      // for MallocRange, etc
#include "internal_logging.h"  // for ASSERT, TCMalloc_Printer, etc
#include "malloc_backtrace.h"
#include "page_heap_allocator.h"  // for PageHeapAllocator
#include "static_vars.h"       // for Static
#include "system-alloc.h"      // for TCMalloc_SystemAlloc, etc

DEFINE_double(tcmalloc_release_rate,
              EnvToDouble("TCMALLOC_RELEASE_RATE", 1.0),
              "Rate at which we release unused memory to the system.  "
              "Zero means we never release memory back to the system.  "
              "Increase this flag to return memory faster; decrease it "
              "to return memory slower.  Reasonable rates are in the "
              "range [0,10]");

DEFINE_int64(tcmalloc_heap_limit_mb,
              EnvToInt("TCMALLOC_HEAP_LIMIT_MB", 0),
              "Limit total size of the process heap to the "
              "specified number of MiB. "
              "When we approach the limit the memory is released "
              "to the system more aggressively (more minor page faults). "
              "Zero means to allocate as long as system allows.");

namespace tcmalloc {

struct SCOPED_LOCKABLE PageHeap::LockingContext {
  PageHeap * const heap;
  size_t grown_by = 0;

  explicit LockingContext(PageHeap* heap, SpinLock* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
      : heap(heap) {
    lock->Lock();
  }
  ~LockingContext() UNLOCK_FUNCTION() {
    heap->HandleUnlock(this);
  }
};


PageHeap::PageHeap(Length smallest_span_size)
    : smallest_span_size_(smallest_span_size),
      pagemap_(MetaDataAlloc),
      scavenge_counter_(0),
      // Start scavenging at kMaxPages list
      release_index_(kMaxPages),
      aggressive_decommit_(false) {
  static_assert(kClassSizesMax <= (1 << PageMapCache::kValuebits));
  // smallest_span_size needs to be power of 2.
  CHECK_CONDITION((smallest_span_size_ & (smallest_span_size_-1)) == 0);
  for (int i = 0; i < kMaxPages; i++) {
    DLL_Init(&free_[i].normal);
    DLL_Init(&free_[i].returned);
  }
}

Span* PageHeap::SearchFreeAndLargeLists(Length n) {
  ASSERT(lock_.IsHeld());
  ASSERT(Check());
  ASSERT(n > 0);

  // Find first size >= n that has a non-empty list
  for (Length s = n; s <= kMaxPages; s++) {
    Span* ll = &free_[s - 1].normal;
    // If we're lucky, ll is non-empty, meaning it has a suitable span.
    if (!DLL_IsEmpty(ll)) {
      ASSERT(ll->next->location == Span::ON_NORMAL_FREELIST);
      return Carve(ll->next, n);
    }
    // Alternatively, maybe there's a usable returned span.
    ll = &free_[s - 1].returned;
    if (!DLL_IsEmpty(ll)) {
      // We did not call EnsureLimit before, to avoid releasing the span
      // that will be taken immediately back.
      // Calling EnsureLimit here is not very expensive, as it fails only if
      // there is no more normal spans (and it fails efficiently)
      // or SystemRelease does not work (there is probably no returned spans).
      if (EnsureLimit(n)) {
        // ll may have became empty due to coalescing
        if (!DLL_IsEmpty(ll)) {
          ASSERT(ll->next->location == Span::ON_RETURNED_FREELIST);
          return Carve(ll->next, n);
        }
      }
    }
  }
  // No luck in free lists, our last chance is in a larger class.
  return AllocLarge(n);  // May be nullptr
}

static const size_t kForcedCoalesceInterval = 128*1024*1024;

Length PageHeap::RoundUpSize(Length n) {
  Length rounded_n = (n + smallest_span_size_ - 1) & ~(smallest_span_size_ - 1);
  if (rounded_n < n) {
    // Overflow happened. So make sure we oom by asking for biggest
    // amount possible.
    return std::numeric_limits::max() & ~(smallest_span_size_ - 1);
  }

  return rounded_n;
}

void PageHeap::HandleUnlock(LockingContext* context) {
  StackTrace* t = nullptr;
  if (context->grown_by) {
    t = Static::stacktrace_allocator()->New();
    t->size = context->grown_by;
  }

  lock_.Unlock();

  if (t) {
    t->depth = tcmalloc::GrabBacktrace(t->stack, kMaxStackDepth-1, 0);
    Static::push_growth_stack(t);
  }
}

Span* PageHeap::NewWithSizeClass(Length n, uint32_t sizeclass) {
  LockingContext context{this, &lock_};

  Span* span = NewLocked(n, &context);
  if (!span) {
    return span;
  }
  InvalidateCachedSizeClass(span->start);
  if (sizeclass) {
    RegisterSizeClass(span, sizeclass);
  }
  return span;
}

Span* PageHeap::NewLocked(Length n, LockingContext* context) {
  ASSERT(lock_.IsHeld());
  ASSERT(Check());
  n = RoundUpSize(n);

  Span* result = SearchFreeAndLargeLists(n);
  if (result != nullptr)
    return result;

  if (stats_.free_bytes != 0 && stats_.unmapped_bytes != 0
      && stats_.free_bytes + stats_.unmapped_bytes >= stats_.system_bytes / 4
      && (stats_.system_bytes / kForcedCoalesceInterval
          != (stats_.system_bytes + (n << kPageShift)) / kForcedCoalesceInterval)) {
    // We're about to grow heap, but there are lots of free pages.
    // tcmalloc's design decision to keep unmapped and free spans
    // separately and never coalesce them means that sometimes there
    // can be free pages span of sufficient size, but it consists of
    // "segments" of different type so page heap search cannot find
    // it. In order to prevent growing heap and wasting memory in such
    // case we're going to unmap all free pages. So that all free
    // spans are maximally coalesced.
    //
    // We're also limiting 'rate' of going into this path to be at
    // most once per 128 megs of heap growth. Otherwise programs that
    // grow heap frequently (and that means by small amount) could be
    // penalized with higher count of minor page faults.
    //
    // See also large_heap_fragmentation_unittest.cc and
    // https://github.com/gperftools/gperftools/issues/371
    ReleaseAtLeastNPages(static_cast(0x7fffffff));

    // then try again. If we are forced to grow heap because of large
    // spans fragmentation and not because of problem described above,
    // then at the very least we've just unmapped free but
    // insufficiently big large spans back to OS. So in case of really
    // unlucky memory fragmentation we'll be consuming virtual address
    // space, but not real memory
    result = SearchFreeAndLargeLists(n);
    if (result != nullptr) return result;
  }

  // Grow the heap and try again.
  if (!GrowHeap(n, context)) {
    ASSERT(stats_.unmapped_bytes+ stats_.committed_bytes==stats_.system_bytes);
    ASSERT(Check());
    // underlying SysAllocator likely set ENOMEM but we can get here
    // due to EnsureLimit so we set it here too.
    //
    // Setting errno to ENOMEM here allows us to avoid dealing with it
    // in fast-path.
    errno = ENOMEM;
    return nullptr;
  }
  return SearchFreeAndLargeLists(n);
}

Span* PageHeap::NewAligned(Length n, Length align_pages) {
  n = RoundUpSize(n);

  // Allocate extra pages and carve off an aligned portion
  const Length alloc = n + align_pages;
  if (alloc < n || alloc < align_pages) {
    // overflow means we asked huge amounts, so lets trigger normal
    // oom handling by asking enough to trigger oom.
    Span* span = New(std::numeric_limits::max());
    CHECK_CONDITION(span == nullptr);
    return nullptr;
  }

  LockingContext context{this, &lock_};

  Span* span = NewLocked(alloc, &context);
  if (PREDICT_FALSE(span == nullptr)) return nullptr;

  // Skip starting portion so that we end up aligned
  Length skip = 0;
  size_t align_bytes = align_pages << kPageShift;
  while ((((span->start+skip) << kPageShift) & (align_bytes - 1)) != 0) {
    skip++;
  }
  ASSERT(skip < alloc);
  if (skip > 0) {
    Span* rest = Split(span, skip);
    DeleteLocked(span);
    span = rest;
  }

  ASSERT(span->length >= n);
  if (span->length > n) {
    Span* trailer = Split(span, n);
    DeleteLocked(trailer);
  }
  InvalidateCachedSizeClass(span->start);
  return span;
}

Span* PageHeap::AllocLarge(Length n) {
  ASSERT(lock_.IsHeld());
  Span *best = nullptr;
  Span *best_normal = nullptr;

  // Create a Span to use as an upper bound.
  Span bound;
  bound.start = 0;
  bound.length = n;

  // First search the NORMAL spans..
  SpanSetIter place = large_normal_.upper_bound(SpanPtrWithLength(&bound));
  if (place != large_normal_.end()) {
    best = place->span;
    best_normal = best;
    ASSERT(best->location == Span::ON_NORMAL_FREELIST);
  }

  // Try to find better fit from RETURNED spans.
  place = large_returned_.upper_bound(SpanPtrWithLength(&bound));
  if (place != large_returned_.end()) {
    Span *c = place->span;
    ASSERT(c->location == Span::ON_RETURNED_FREELIST);
    if (best_normal == nullptr
        || c->length < best->length)
      best = place->span;
  }

  if (best == best_normal) {
    return best == nullptr ? nullptr : Carve(best, n);
  }

  // best comes from RETURNED set.

  if (EnsureLimit(n, false)) {
    return Carve(best, n);
  }

  if (EnsureLimit(n, true)) {
    // best could have been destroyed by coalescing.
    // best_normal is not a best-fit, and it could be destroyed as well.
    // We retry, the limit is already ensured:
    return AllocLarge(n);
  }

  // If best_normal existed, EnsureLimit would succeeded:
  ASSERT(best_normal == nullptr);
  // We are not allowed to take best from returned list.
  return nullptr;
}

Span* PageHeap::Split(Span* span, Length n) {
  ASSERT(lock_.IsHeld());
  ASSERT(0 < n);
  ASSERT(n < span->length);
  ASSERT(span->location == Span::IN_USE);
  ASSERT(span->sizeclass == 0);

  const int extra = span->length - n;
  Span* leftover = NewSpan(span->start + n, extra);
  ASSERT(leftover->location == Span::IN_USE);
  RecordSpan(leftover);
  pagemap_.set(span->start + n - 1, span); // Update map from pageid to span
  span->length = n;

  return leftover;
}

void PageHeap::CommitSpan(Span* span) {
  ++stats_.commit_count;

  TCMalloc_SystemCommit(reinterpret_cast(span->start << kPageShift),
                        static_cast(span->length << kPageShift));
  stats_.committed_bytes += span->length << kPageShift;
  stats_.total_commit_bytes += (span->length << kPageShift);
}

bool PageHeap::DecommitSpan(Span* span) {
  ++stats_.decommit_count;

  bool rv = TCMalloc_SystemRelease(reinterpret_cast(span->start << kPageShift),
                                   static_cast(span->length << kPageShift));
  if (rv) {
    stats_.committed_bytes -= span->length << kPageShift;
    stats_.total_decommit_bytes += (span->length << kPageShift);
  }

  return rv;
}

Span* PageHeap::Carve(Span* span, Length n) {
  ASSERT(n > 0);
  ASSERT(span->location != Span::IN_USE);
  const int old_location = span->location;
  RemoveFromFreeList(span);
  span->location = Span::IN_USE;

  const int extra = span->length - n;
  ASSERT(extra >= 0);
  if (extra > 0) {
    Span* leftover = NewSpan(span->start + n, extra);
    leftover->location = old_location;
    RecordSpan(leftover);

    // The previous span of |leftover| was just splitted -- no need to
    // coalesce them. The next span of |leftover| was not previously coalesced
    // with |span|, i.e. is nullptr or has got location other than |old_location|.
#ifndef NDEBUG
    const PageID p = leftover->start;
    const Length len = leftover->length;
    Span* next = GetDescriptor(p+len);
    ASSERT (next == nullptr ||
            next->location == Span::IN_USE ||
            next->location != leftover->location);
#endif

    PrependToFreeList(leftover);  // Skip coalescing - no candidates possible
    span->length = n;
    pagemap_.set(span->start + n - 1, span);
  }
  ASSERT(Check());
  if (old_location == Span::ON_RETURNED_FREELIST) {
    // We need to recommit this address space.
    CommitSpan(span);
  }
  ASSERT(span->location == Span::IN_USE);
  ASSERT(span->length == n);
  ASSERT(stats_.unmapped_bytes+ stats_.committed_bytes==stats_.system_bytes);
  return span;
}

void PageHeap::Delete(Span* span) {
  SpinLockHolder h(&lock_);
  DeleteLocked(span);
}

void PageHeap::DeleteLocked(Span* span) {
  ASSERT(lock_.IsHeld());
  ASSERT(Check());
  ASSERT(span->location == Span::IN_USE);
  ASSERT(span->length > 0);
  ASSERT(GetDescriptor(span->start) == span);
  ASSERT(GetDescriptor(span->start + span->length - 1) == span);
  const Length n = span->length;
  span->sizeclass = 0;
  span->sample = 0;
  span->location = Span::ON_NORMAL_FREELIST;
  MergeIntoFreeList(span);  // Coalesces if possible
  IncrementalScavenge(n);
  ASSERT(stats_.unmapped_bytes+ stats_.committed_bytes==stats_.system_bytes);
  ASSERT(Check());
}

// Given span we're about to free and other span (still on free list),
// checks if 'other' span is mergable with 'span'. If it is, removes
// other span from free list, performs aggressive decommit if
// necessary and returns 'other' span. Otherwise 'other' span cannot
// be merged and is left untouched. In that case nullptr is returned.
Span* PageHeap::CheckAndHandlePreMerge(Span* span, Span* other) {
  if (other == nullptr) {
    return other;
  }
  // if we're in aggressive decommit mode and span is decommitted,
  // then we try to decommit adjacent span.
  if (aggressive_decommit_ && other->location == Span::ON_NORMAL_FREELIST
      && span->location == Span::ON_RETURNED_FREELIST) {
    bool worked = DecommitSpan(other);
    if (!worked) {
      return nullptr;
    }
  } else if (other->location != span->location) {
    return nullptr;
  }

  RemoveFromFreeList(other);
  return other;
}

void PageHeap::MergeIntoFreeList(Span* span) {
  ASSERT(lock_.IsHeld());
  ASSERT(span->location != Span::IN_USE);

  // Coalesce -- we guarantee that "p" != 0, so no bounds checking
  // necessary.  We do not bother resetting the stale pagemap
  // entries for the pieces we are merging together because we only
  // care about the pagemap entries for the boundaries.
  //
  // Note: depending on aggressive_decommit_ mode we allow only
  // similar spans to be coalesced.
  //
  // The following applies if aggressive_decommit_ is enabled:
  //
  // TODO(jar): "Always decommit" causes some extra calls to commit when we are
  // called in GrowHeap() during an allocation :-/.  We need to eval the cost of
  // that oscillation, and possibly do something to reduce it.

  // TODO(jar): We need a better strategy for deciding to commit, or decommit,
  // based on memory usage and free heap sizes.

  const PageID p = span->start;
  const Length n = span->length;

  if (aggressive_decommit_ && span->location == Span::ON_NORMAL_FREELIST) {
    if (DecommitSpan(span)) {
      span->location = Span::ON_RETURNED_FREELIST;
    }
  }

  Span* prev = CheckAndHandlePreMerge(span, GetDescriptor(p-1));
  if (prev != nullptr) {
    // Merge preceding span into this span
    ASSERT(prev->start + prev->length == p);
    const Length len = prev->length;
    DeleteSpan(prev);
    span->start -= len;
    span->length += len;
    pagemap_.set(span->start, span);
  }
  Span* next = CheckAndHandlePreMerge(span, GetDescriptor(p+n));
  if (next != nullptr) {
    // Merge next span into this span
    ASSERT(next->start == p+n);
    const Length len = next->length;
    DeleteSpan(next);
    span->length += len;
    pagemap_.set(span->start + span->length - 1, span);
  }

  PrependToFreeList(span);
}

void PageHeap::PrependToFreeList(Span* span) {
  ASSERT(lock_.IsHeld());
  ASSERT(span->location != Span::IN_USE);
  if (span->location == Span::ON_NORMAL_FREELIST)
    stats_.free_bytes += (span->length << kPageShift);
  else
    stats_.unmapped_bytes += (span->length << kPageShift);

  if (span->length > kMaxPages) {
    SpanSet *set = &large_normal_;
    if (span->location == Span::ON_RETURNED_FREELIST)
      set = &large_returned_;
    std::pair p =
        set->insert(SpanPtrWithLength(span));
    ASSERT(p.second); // We never have duplicates since span->start is unique.
    span->SetSpanSetIterator(p.first);
    return;
  }

  SpanList* list = &free_[span->length - 1];
  if (span->location == Span::ON_NORMAL_FREELIST) {
    DLL_Prepend(&list->normal, span);
  } else {
    DLL_Prepend(&list->returned, span);
  }
}

void PageHeap::RemoveFromFreeList(Span* span) {
  ASSERT(lock_.IsHeld());
  ASSERT(span->location != Span::IN_USE);
  if (span->location == Span::ON_NORMAL_FREELIST) {
    stats_.free_bytes -= (span->length << kPageShift);
  } else {
    stats_.unmapped_bytes -= (span->length << kPageShift);
  }
  if (span->length > kMaxPages) {
    SpanSet *set = &large_normal_;
    if (span->location == Span::ON_RETURNED_FREELIST)
      set = &large_returned_;
    SpanSetIter iter = span->ExtractSpanSetIterator();
    ASSERT(iter->span == span);
    ASSERT(set->find(SpanPtrWithLength(span)) == iter);
    set->erase(iter);
  } else {
    DLL_Remove(span);
  }
}

void PageHeap::IncrementalScavenge(Length n) {
  ASSERT(lock_.IsHeld());
  // Fast path; not yet time to release memory
  scavenge_counter_ -= n;
  if (scavenge_counter_ >= 0) return;  // Not yet time to scavenge

  const double rate = FLAGS_tcmalloc_release_rate;
  if (rate <= 1e-6) {
    // Tiny release rate means that releasing is disabled.
    scavenge_counter_ = kDefaultReleaseDelay;
    return;
  }

  ++stats_.scavenge_count;

  Length released_pages = ReleaseAtLeastNPages(1);

  if (released_pages == 0) {
    // Nothing to scavenge, delay for a while.
    scavenge_counter_ = kDefaultReleaseDelay;
  } else {
    // Compute how long to wait until we return memory.
    // FLAGS_tcmalloc_release_rate==1 means wait for 1000 pages
    // after releasing one page.
    const double mult = 1000.0 / rate;
    double wait = mult * static_cast(released_pages);
    if (wait > kMaxReleaseDelay) {
      // Avoid overflow and bound to reasonable range.
      wait = kMaxReleaseDelay;
    }
    scavenge_counter_ = static_cast(wait);
  }
}

Length PageHeap::ReleaseSpan(Span* s) {
  ASSERT(s->location == Span::ON_NORMAL_FREELIST);

  if (DecommitSpan(s)) {
    RemoveFromFreeList(s);
    const Length n = s->length;
    s->location = Span::ON_RETURNED_FREELIST;
    MergeIntoFreeList(s);  // Coalesces if possible.
    return n;
  }

  return 0;
}

Length PageHeap::ReleaseAtLeastNPages(Length num_pages) {
  ASSERT(lock_.IsHeld());
  Length released_pages = 0;

  // Round robin through the lists of free spans, releasing a
  // span from each list.  Stop after releasing at least num_pages
  // or when there is nothing more to release.
  while (released_pages < num_pages && stats_.free_bytes > 0) {
    for (int i = 0; i < kMaxPages+1 && released_pages < num_pages;
         i++, release_index_++) {
      Span *s;
      if (release_index_ > kMaxPages) release_index_ = 0;

      if (release_index_ == kMaxPages) {
        if (large_normal_.empty()) {
          continue;
        }
        s = (large_normal_.begin())->span;
      } else {
        SpanList* slist = &free_[release_index_];
        if (DLL_IsEmpty(&slist->normal)) {
          continue;
        }
        s = slist->normal.prev;
      }
      // TODO(todd) if the remaining number of pages to release
      // is significantly smaller than s->length, and s is on the
      // large freelist, should we carve s instead of releasing?
      // the whole thing?
      Length released_len = ReleaseSpan(s);
      // Some systems do not support release
      if (released_len == 0) return released_pages;
      released_pages += released_len;
    }
  }
  return released_pages;
}

bool PageHeap::EnsureLimit(Length n, bool withRelease) {
  ASSERT(lock_.IsHeld());
  Length limit = (FLAGS_tcmalloc_heap_limit_mb*1024*1024) >> kPageShift;
  if (limit == 0) return true; //there is no limit

  // We do not use stats_.system_bytes because it does not take
  // MetaDataAllocs into account.
  Length takenPages = TCMalloc_SystemTaken >> kPageShift;
  //XXX takenPages may be slightly bigger than limit for two reasons:
  //* MetaDataAllocs ignore the limit (it is not easy to handle
  //  out of memory there)
  //* sys_alloc may round allocation up to huge page size,
  //  although smaller limit was ensured

  ASSERT(takenPages >= stats_.unmapped_bytes >> kPageShift);
  takenPages -= stats_.unmapped_bytes >> kPageShift;

  if (takenPages + n > limit && withRelease) {
    takenPages -= ReleaseAtLeastNPages(takenPages + n - limit);
  }

  return takenPages + n <= limit;
}

void PageHeap::RegisterSizeClass(Span* span, uint32_t sc) {
  // Associate span object with all interior pages as well
  ASSERT(span->location == Span::IN_USE);
  ASSERT(GetDescriptor(span->start) == span);
  ASSERT(GetDescriptor(span->start+span->length-1) == span);
  span->sizeclass = sc;
  for (Length i = 1; i < span->length-1; i++) {
    pagemap_.set(span->start+i, span);
  }
}

void PageHeap::GetSmallSpanStatsLocked(SmallSpanStats* result) {
  ASSERT(lock_.IsHeld());
  for (int i = 0; i < kMaxPages; i++) {
    result->normal_length[i] = DLL_Length(&free_[i].normal);
    result->returned_length[i] = DLL_Length(&free_[i].returned);
  }
}

void PageHeap::GetLargeSpanStatsLocked(LargeSpanStats* result) {
  ASSERT(lock_.IsHeld());
  result->spans = 0;
  result->normal_pages = 0;
  result->returned_pages = 0;
  for (SpanSetIter it = large_normal_.begin(); it != large_normal_.end(); ++it) {
    result->normal_pages += it->length;
    result->spans++;
  }
  for (SpanSetIter it = large_returned_.begin(); it != large_returned_.end(); ++it) {
    result->returned_pages += it->length;
    result->spans++;
  }
}

bool PageHeap::GetNextRange(PageID start, base::MallocRange* r) {
  ASSERT(lock_.IsHeld());
  Span* span = reinterpret_cast(pagemap_.Next(start));
  if (span == nullptr) {
    return false;
  }
  r->address = span->start << kPageShift;
  r->length = span->length << kPageShift;
  r->fraction = 0;
  switch (span->location) {
    case Span::IN_USE:
      r->type = base::MallocRange::INUSE;
      r->fraction = 1;
      if (span->sizeclass > 0) {
        // Only some of the objects in this span may be in use.
        const size_t osize = Static::sizemap()->class_to_size(span->sizeclass);
        r->fraction = (1.0 * osize * span->refcount) / r->length;
      }
      break;
    case Span::ON_NORMAL_FREELIST:
      r->type = base::MallocRange::FREE;
      break;
    case Span::ON_RETURNED_FREELIST:
      r->type = base::MallocRange::UNMAPPED;
      break;
    default:
      r->type = base::MallocRange::UNKNOWN;
      break;
  }
  return true;
}

bool PageHeap::GrowHeap(Length n, LockingContext* context) {
  ASSERT(lock_.IsHeld());
  ASSERT(kMaxPages >= kMinSystemAlloc);
  if (n > kMaxValidPages) return false;
  Length ask = (n>kMinSystemAlloc) ? n : static_cast(kMinSystemAlloc);
  size_t actual_size;
  void* ptr = nullptr;
  if (EnsureLimit(ask)) {
      ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize);
  }
  if (ptr == nullptr) {
    if (n < ask) {
      // Try growing just "n" pages
      ask = n;
      if (EnsureLimit(ask)) {
        ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize);
      }
    }
    if (ptr == nullptr) return false;
  }
  ask = actual_size >> kPageShift;
  context->grown_by += ask << kPageShift;

  ++stats_.reserve_count;
  ++stats_.commit_count;

  uint64_t old_system_bytes = stats_.system_bytes;
  stats_.system_bytes += (ask << kPageShift);
  stats_.committed_bytes += (ask << kPageShift);

  stats_.total_commit_bytes += (ask << kPageShift);
  stats_.total_reserve_bytes += (ask << kPageShift);

  const PageID p = reinterpret_cast(ptr) >> kPageShift;
  ASSERT(p > 0);

  // If we have already a lot of pages allocated, just pre allocate a bunch of
  // memory for the page map. This prevents fragmentation by pagemap metadata
  // when a program keeps allocating and freeing large blocks.

  if (old_system_bytes < kPageMapBigAllocationThreshold
      && stats_.system_bytes >= kPageMapBigAllocationThreshold) {
    pagemap_.PreallocateMoreMemory();
  }

  // Make sure pagemap_ has entries for all of the new pages.
  // Plus ensure one before and one after so coalescing code
  // does not need bounds-checking.
  if (pagemap_.Ensure(p-1, ask+2)) {
    // Pretend the new area is allocated and then Delete() it to cause
    // any necessary coalescing to occur.
    Span* span = NewSpan(p, ask);
    RecordSpan(span);
    DeleteLocked(span);
    ASSERT(stats_.unmapped_bytes+ stats_.committed_bytes==stats_.system_bytes);
    ASSERT(Check());
    return true;
  } else {
    // We could not allocate memory within "pagemap_"
    // TODO: Once we can return memory to the system, return the new span
    return false;
  }
}

bool PageHeap::Check() {
  ASSERT(lock_.IsHeld());
  return true;
}

bool PageHeap::CheckExpensive() {
  bool result = Check();
  CheckSet(&large_normal_, kMaxPages + 1, Span::ON_NORMAL_FREELIST);
  CheckSet(&large_returned_, kMaxPages + 1, Span::ON_RETURNED_FREELIST);
  for (int s = 1; s <= kMaxPages; s++) {
    CheckList(&free_[s - 1].normal, s, s, Span::ON_NORMAL_FREELIST);
    CheckList(&free_[s - 1].returned, s, s, Span::ON_RETURNED_FREELIST);
  }
  return result;
}

bool PageHeap::CheckList(Span* list, Length min_pages, Length max_pages,
                         int freelist) {
  for (Span* s = list->next; s != list; s = s->next) {
    CHECK_CONDITION(s->location == freelist);  // NORMAL or RETURNED
    CHECK_CONDITION(s->length >= min_pages);
    CHECK_CONDITION(s->length <= max_pages);
    CHECK_CONDITION(GetDescriptor(s->start) == s);
    CHECK_CONDITION(GetDescriptor(s->start+s->length-1) == s);
  }
  return true;
}

bool PageHeap::CheckSet(SpanSet* spanset, Length min_pages,int freelist) {
  for (SpanSetIter it = spanset->begin(); it != spanset->end(); ++it) {
    Span* s = it->span;
    CHECK_CONDITION(s->length == it->length);
    CHECK_CONDITION(s->location == freelist);  // NORMAL or RETURNED
    CHECK_CONDITION(s->length >= min_pages);
    CHECK_CONDITION(GetDescriptor(s->start) == s);
    CHECK_CONDITION(GetDescriptor(s->start+s->length-1) == s);
  }
  return true;
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/page_heap.h000066400000000000000000000330671513545575200207100ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#ifndef TCMALLOC_PAGE_HEAP_H_
#define TCMALLOC_PAGE_HEAP_H_

#include 
#include                      // for size_t
#include                      // for uint64_t, int64_t, uint16_t
#include "base/basictypes.h"
#include "base/spinlock.h"
#include "base/thread_annotations.h"
#include "common.h"
#include "packed-cache-inl.h"
#include "pagemap.h"
#include "span.h"

// We need to dllexport PageHeap just for the unittest.  MSVC complains
// that we don't dllexport the PageHeap members, but we don't need to
// test those, so I just suppress this warning.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif

namespace base {
struct MallocRange;
}

namespace tcmalloc {

// -------------------------------------------------------------------------
// Map from page-id to per-page data
// -------------------------------------------------------------------------

// We use PageMap2<> for 32-bit and PageMap3<> for 64-bit machines.
// We also use a simple one-level cache for hot PageID-to-sizeclass mappings,
// because sometimes the sizeclass is all the information we need.

// Selector class -- general selector uses 3-level map
template  class MapSelector {
 public:
  typedef TCMalloc_PageMap3 Type;
};

#ifndef TCMALLOC_SMALL_BUT_SLOW
// x86-64 and arm64 are using 48 bits of address space. So we can use
// just two level map, but since initial ram consumption of this mode
// is a bit on the higher side, we opt-out of it in
// TCMALLOC_SMALL_BUT_SLOW mode.
template <> class MapSelector<48> {
 public:
  typedef TCMalloc_PageMap2<48-kPageShift> Type;
};

#endif // TCMALLOC_SMALL_BUT_SLOW

// A two-level map for 32-bit machines
template <> class MapSelector<32> {
 public:
  typedef TCMalloc_PageMap2<32-kPageShift> Type;
};

// -------------------------------------------------------------------------
// Page-level allocator
//  * Eager coalescing
//
// Heap for page-level allocation.  We allow allocating and freeing a
// contiguous runs of pages (called a "span").
// -------------------------------------------------------------------------

class PageHeap {
 public:
  PageHeap() : PageHeap(1) {}
  PageHeap(Length smallest_span_size);

  SpinLock* pageheap_lock() {
    return &lock_;
  }

  // Aligns given size up to be multiple of smallest_span_size.
  Length RoundUpSize(Length n);

  // Allocate a run of "n" pages.  Returns zero if out of memory.
  // Caller should not pass "n == 0" -- instead, n should have
  // been rounded up already.
  Span* New(Length n) {
    return NewWithSizeClass(n, 0);
  }

  Span* NewWithSizeClass(Length n, uint32_t sizeclass);

  // Same as above but with alignment. Requires page heap
  // lock, like New above.
  Span* NewAligned(Length n, Length align_pages);

  // Delete the span "[p, p+n-1]".
  // REQUIRES: span was returned by earlier call to New() and
  //           has not yet been deleted.
  void Delete(Span* span);

  template 
  void PrepareAndDelete(Span* span, const Body& body) LOCKS_EXCLUDED(lock_) {
    SpinLockHolder h(&lock_);
    body();
    DeleteLocked(span);
  }

  // Mark an allocated span as being used for small objects of the
  // specified size-class.
  // REQUIRES: span was returned by an earlier call to New()
  //           and has not yet been deleted.
  void RegisterSizeClass(Span* span, uint32_t sc);

  Span* SplitForTest(Span* span, Length n) {
    SpinLockHolder l(&lock_);
    return Split(span, n);
  }

  // Return the descriptor for the specified page.  Returns nullptr if
  // this PageID was not allocated previously.
  ALWAYS_INLINE
  Span* GetDescriptor(PageID p) const {
    return reinterpret_cast(pagemap_.get(p));
  }

  // If this page heap is managing a range with starting page # >= start,
  // store info about the range in *r and return true.  Else return false.
  bool GetNextRange(PageID start, base::MallocRange* r);

  // Page heap statistics
  struct Stats {
    Stats() : system_bytes(0), free_bytes(0), unmapped_bytes(0), committed_bytes(0),
        scavenge_count(0), commit_count(0), total_commit_bytes(0),
        decommit_count(0), total_decommit_bytes(0),
        reserve_count(0), total_reserve_bytes(0) {}
    uint64_t system_bytes;    // Total bytes allocated from system
    uint64_t free_bytes;      // Total bytes on normal freelists
    uint64_t unmapped_bytes;  // Total bytes on returned freelists
    uint64_t committed_bytes;  // Bytes committed, always <= system_bytes_.

    uint64_t scavenge_count;   // Number of times scavagened flush pages

    uint64_t commit_count;          // Number of virtual memory commits
    uint64_t total_commit_bytes;    // Bytes committed in lifetime of process
    uint64_t decommit_count;        // Number of virtual memory decommits
    uint64_t total_decommit_bytes;  // Bytes decommitted in lifetime of process

    uint64_t reserve_count;         // Number of virtual memory reserves
    uint64_t total_reserve_bytes;   // Bytes reserved in lifetime of process
  };
  inline Stats StatsLocked() const { return stats_; }

  struct SmallSpanStats {
    // For each free list of small spans, the length (in spans) of the
    // normal and returned free lists for that size.
    //
    // NOTE: index 'i' accounts the number of spans of length 'i + 1'.
    int64_t normal_length[kMaxPages];
    int64_t returned_length[kMaxPages];
  };
  void GetSmallSpanStatsLocked(SmallSpanStats* result);

  // Stats for free large spans (i.e., spans with more than kMaxPages pages).
  struct LargeSpanStats {
    int64_t spans;           // Number of such spans
    int64_t normal_pages;    // Combined page length of normal large spans
    int64_t returned_pages;  // Combined page length of unmapped spans
  };
  void GetLargeSpanStatsLocked(LargeSpanStats* result);

  bool Check();
  // Like Check() but does some more comprehensive checking.
  bool CheckExpensive();
  bool CheckList(Span* list, Length min_pages, Length max_pages,
                 int freelist);  // ON_NORMAL_FREELIST or ON_RETURNED_FREELIST
  bool CheckSet(SpanSet *s, Length min_pages, int freelist);

  // Try to release at least num_pages for reuse by the OS.  Returns
  // the actual number of pages released, which may be less than
  // num_pages if there weren't enough pages to release. The result
  // may also be larger than num_pages since page_heap might decide to
  // release one large range instead of fragmenting it into two
  // smaller released and unreleased ranges.
  Length ReleaseAtLeastNPages(Length num_pages);

  // Reads and writes to pagemap_cache_ do not require locking.
  bool TryGetSizeClass(PageID p, uint32_t* out) const {
    return pagemap_cache_.TryGet(p, out);
  }
  void SetCachedSizeClass(PageID p, uint32_t cl) {
    ASSERT(cl != 0);
    pagemap_cache_.Put(p, cl);
  }
  void InvalidateCachedSizeClass(PageID p) { pagemap_cache_.Invalidate(p); }
  uint32_t GetSizeClassOrZero(PageID p) const {
    uint32_t cached_value;
    if (!TryGetSizeClass(p, &cached_value)) {
      cached_value = 0;
    }
    return cached_value;
  }

  bool GetAggressiveDecommit(void) {return aggressive_decommit_;}
  void SetAggressiveDecommit(bool aggressive_decommit) {
    aggressive_decommit_ = aggressive_decommit;
  }

 private:
  struct LockingContext;

  void HandleUnlock(LockingContext* context) UNLOCK_FUNCTION(lock_) ;

  // Allocates a big block of memory for the pagemap once we reach more than
  // 128MB
  static const size_t kPageMapBigAllocationThreshold = 128 << 20;

  // Minimum number of pages to fetch from system at a time.  Must be
  // significantly bigger than kBlockSize to amortize system-call
  // overhead, and also to reduce external fragementation.  Also, we
  // should keep this value big because various incarnations of Linux
  // have small limits on the number of mmap() regions per
  // address-space.
  // REQUIRED: kMinSystemAlloc <= kMaxPages;
  static const int kMinSystemAlloc = kMaxPages;

  // Never delay scavenging for more than the following number of
  // deallocated pages.  With 4K pages, this comes to 4GB of
  // deallocation.
  static const int kMaxReleaseDelay = 1 << 20;

  // If there is nothing to release, wait for so many pages before
  // scavenging again.  With 4K pages, this comes to 1GB of memory.
  static const int kDefaultReleaseDelay = 1 << 18;

  const Length smallest_span_size_;

  SpinLock lock_;

  // Pick the appropriate map and cache types based on pointer size
  typedef MapSelector::Type PageMap;
  typedef PackedCache PageMapCache;
  mutable PageMapCache pagemap_cache_;
  PageMap pagemap_;

  // We segregate spans of a given size into two circular linked
  // lists: one for normal spans, and one for spans whose memory
  // has been returned to the system.
  struct SpanList {
    Span        normal;
    Span        returned;
  };

  // Sets of spans with length > kMaxPages.
  //
  // Rather than using a linked list, we use sets here for efficient
  // best-fit search.
  SpanSet large_normal_;
  SpanSet large_returned_;

  // Array mapping from span length to a doubly linked list of free spans
  //
  // NOTE: index 'i' stores spans of length 'i + 1'.
  SpanList free_[kMaxPages];

  // Statistics on system, free, and unmapped bytes
  Stats stats_;

  Span* NewLocked(Length n, LockingContext* context) EXCLUSIVE_LOCKS_REQUIRED(lock_);
  void DeleteLocked(Span* span) EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // Split an allocated span into two spans: one of length "n" pages
  // followed by another span of length "span->length - n" pages.
  // Modifies "*span" to point to the first span of length "n" pages.
  // Returns a pointer to the second span.
  //
  // REQUIRES: "0 < n < span->length"
  // REQUIRES: span->location == IN_USE
  // REQUIRES: span->sizeclass == 0
  Span* Split(Span* span, Length n);

  Span* SearchFreeAndLargeLists(Length n);

  bool GrowHeap(Length n, LockingContext* context) EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // REQUIRES: span->length >= n
  // REQUIRES: span->location != IN_USE
  // Remove span from its free list, and move any leftover part of
  // span into appropriate free lists.  Also update "span" to have
  // length exactly "n" and mark it as non-free so it can be returned
  // to the client.  After all that, decrease free_pages_ by n and
  // return span.
  Span* Carve(Span* span, Length n);

  void RecordSpan(Span* span) {
    pagemap_.set(span->start, span);
    if (span->length > 1) {
      pagemap_.set(span->start + span->length - 1, span);
    }
  }

  // Allocate a large span of length == n.  If successful, returns a
  // span of exactly the specified length.  Else, returns nullptr.
  Span* AllocLarge(Length n);

  // Coalesce span with neighboring spans if possible, prepend to
  // appropriate free list, and adjust stats.
  void MergeIntoFreeList(Span* span);

  // Commit the span.
  void CommitSpan(Span* span);

  // Decommit the span.
  bool DecommitSpan(Span* span);

  // Prepends span to appropriate free list, and adjusts stats.
  void PrependToFreeList(Span* span);

  // Removes span from its free list, and adjust stats.
  void RemoveFromFreeList(Span* span);

  // Incrementally release some memory to the system.
  // IncrementalScavenge(n) is called whenever n pages are freed.
  void IncrementalScavenge(Length n);

  // Attempts to decommit 's' and move it to the returned freelist.
  //
  // Returns the length of the Span or zero if release failed.
  //
  // REQUIRES: 's' must be on the NORMAL freelist.
  Length ReleaseSpan(Span *s);

  // Checks if we are allowed to take more memory from the system.
  // If limit is reached and allowRelease is true, tries to release
  // some unused spans.
  bool EnsureLimit(Length n, bool allowRelease = true);

  Span* CheckAndHandlePreMerge(Span *span, Span *other);

  // Number of pages to deallocate before doing more scavenging
  int64_t scavenge_counter_;

  // Index of last free list where we released memory to the OS.
  int release_index_;

  bool aggressive_decommit_;
};

}  // namespace tcmalloc

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif  // TCMALLOC_PAGE_HEAP_H_
gperftools-gperftools-2.18/src/page_heap_allocator.h000066400000000000000000000140101513545575200227330ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#ifndef TCMALLOC_PAGE_HEAP_ALLOCATOR_H_
#define TCMALLOC_PAGE_HEAP_ALLOCATOR_H_

#include             // for size_t

#include "common.h"            // for MetaDataAlloc
#include "internal_logging.h"  // for ASSERT

namespace tcmalloc {

// Simple allocator for objects of a specified type.  External locking
// is required before accessing one of these objects.
template 
class PageHeapAllocator {
 public:
  constexpr PageHeapAllocator() = default;

  // We use an explicit Init function because these variables are statically
  // allocated and their constructors might not have run by the time some
  // other static variable tries to allocate memory.
  void Init() {
    ASSERT(sizeof(T) <= kAllocIncrement);
    inuse_ = 0;
    free_area_ = nullptr;
    free_avail_ = 0;
    free_list_ = nullptr;
    // Reserve some space at the beginning to avoid fragmentation.
    Delete(New());
  }

  T* New() {
    // Consult free list
    void* result;
    if (free_list_ != nullptr) {
      result = free_list_;
      free_list_ = *(reinterpret_cast(result));
    } else {
      if (free_avail_ < sizeof(T)) {
        // Need more room. We assume that MetaDataAlloc returns
        // suitably aligned memory.
        free_area_ = reinterpret_cast(MetaDataAlloc(kAllocIncrement));
        if (free_area_ == nullptr) {
          Log(kCrash, __FILE__, __LINE__,
              "FATAL ERROR: Out of memory trying to allocate internal "
              "tcmalloc data (bytes, object-size)",
              kAllocIncrement, sizeof(T));
        }
        free_avail_ = kAllocIncrement;
      }
      result = free_area_;
      free_area_ += sizeof(T);
      free_avail_ -= sizeof(T);
    }
    inuse_++;
    return reinterpret_cast(result);
  }

  void Delete(T* p) {
#ifndef NDEBUG
    memset(static_cast(p), 0xAA, sizeof(T));
#endif
    *(reinterpret_cast(p)) = free_list_;
    free_list_ = p;
    inuse_--;
  }

  int inuse() const { return inuse_; }

 private:
  // How much to allocate from system at a time
  static const int kAllocIncrement = 128 << 10;

  // Free area from which to carve new objects
  char* free_area_;
  size_t free_avail_;

  // Free list of already carved objects
  void* free_list_;

  // Number of allocated but unfreed objects
  int inuse_;
};

// STL-compatible allocator which forwards allocations to a PageHeapAllocator.
//
// Like PageHeapAllocator, this requires external synchronization. To avoid multiple
// separate STLPageHeapAllocator from sharing the same underlying PageHeapAllocator,
// the |LockingTag| template argument should be used. Template instantiations with
// different locking tags can safely be used concurrently.
template 
class STLPageHeapAllocator {
 public:
  typedef size_t     size_type;
  typedef ptrdiff_t  difference_type;
  typedef T*         pointer;
  typedef const T*   const_pointer;
  typedef T&         reference;
  typedef const T&   const_reference;
  typedef T          value_type;

  template  struct rebind {
    typedef STLPageHeapAllocator other;
  };

  STLPageHeapAllocator() { }
  STLPageHeapAllocator(const STLPageHeapAllocator&) { }
  template  STLPageHeapAllocator(const STLPageHeapAllocator&) { }
  ~STLPageHeapAllocator() { }

  pointer address(reference x) const { return &x; }
  const_pointer address(const_reference x) const { return &x; }

  size_type max_size() const { return size_t(-1) / sizeof(T); }

  void construct(pointer p, const T& val) { ::new(p) T(val); }
  void construct(pointer p) { ::new(p) T(); }
  void destroy(pointer p) { p->~T(); }

  // There's no state, so these allocators are always equal
  bool operator==(const STLPageHeapAllocator&) const { return true; }
  bool operator!=(const STLPageHeapAllocator&) const { return false; }

  pointer allocate(size_type n, const void* = 0) {
    if (!underlying_.initialized) {
      underlying_.allocator.Init();
      underlying_.initialized = true;
    }

    CHECK_CONDITION(n == 1);
    return underlying_.allocator.New();
  }
  void deallocate(pointer p, size_type n) {
    CHECK_CONDITION(n == 1);
    underlying_.allocator.Delete(p);
  }

 private:
  struct Storage {
    constexpr Storage() = default;
    PageHeapAllocator allocator;
    bool initialized;
  };
  static inline Storage underlying_;
};

}  // namespace tcmalloc

#endif  // TCMALLOC_PAGE_HEAP_ALLOCATOR_H_
gperftools-gperftools-2.18/src/pagemap.h000066400000000000000000000235631513545575200204110ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 
//
// A data structure used by the caching malloc.  It maps from page# to
// a pointer that contains info about that page.  We use two
// representations: one for 32-bit addresses, and another for 64 bit
// addresses.  Both representations provide the same interface.  The
// first representation is implemented as a flat array, the seconds as
// a three-level radix tree that strips away approximately 1/3rd of
// the bits every time.
//
// The BITS parameter should be the number of bits required to hold
// a page number.  E.g., with 32 bit pointers and 4K pages (i.e.,
// page offset fits in lower 12 bits), BITS == 20.

#ifndef TCMALLOC_PAGEMAP_H_
#define TCMALLOC_PAGEMAP_H_

#include "config.h"

#include                      // for size_t
#include                      // for memset
#include 

#include "base/basictypes.h"
#include "internal_logging.h"  // for ASSERT

// Single-level array
template 
class TCMalloc_PageMap1 {
 private:
  static const int LENGTH = 1 << BITS;

  void** array_;

 public:
  typedef uintptr_t Number;

  explicit TCMalloc_PageMap1(void* (*allocator)(size_t)) {
    array_ = reinterpret_cast((*allocator)(sizeof(void*) << BITS));
    memset(array_, 0, sizeof(void*) << BITS);
  }

  // Ensure that the map contains initialized entries "x .. x+n-1".
  // Returns true if successful, false if we could not allocate memory.
  bool Ensure(Number x, size_t n) {
    // Nothing to do since flat array was allocated at start.  All
    // that's left is to check for overflow (that is, we don't want to
    // ensure a number y where array_[y] would be an out-of-bounds
    // access).
    return n <= LENGTH - x;   // an overflow-free way to do "x + n <= LENGTH"
  }

  void PreallocateMoreMemory() {}

  // Return the current value for KEY.  Returns nullptr if not yet
  // set, or if k is out of range.
  ALWAYS_INLINE
  void* get(Number k) const {
    if ((k >> BITS) > 0) {
      return nullptr;
    }
    return array_[k];
  }

  // REQUIRES "k" is in range "[0,2^BITS-1]".
  // REQUIRES "k" has been ensured before.
  //
  // Sets the value 'v' for key 'k'.
  void set(Number k, void* v) {
    array_[k] = v;
  }

  // Return the first non-nullptr pointer found in this map for a page
  // number >= k.  Returns nullptr if no such number is found.
  void* Next(Number k) const {
    while (k < (1 << BITS)) {
      if (array_[k] != nullptr) return array_[k];
      k++;
    }
    return nullptr;
  }
};

// Two-level radix tree
template 
class TCMalloc_PageMap2 {
 private:
  static const int LEAF_BITS = (BITS + 1) / 2;
  static const int LEAF_LENGTH = 1 << LEAF_BITS;

  static const int ROOT_BITS = BITS - LEAF_BITS;
  static const int ROOT_LENGTH = 1 << ROOT_BITS;

  // Leaf node
  struct Leaf {
    void* values[LEAF_LENGTH];
  };

  Leaf* root_[ROOT_LENGTH];             // Pointers to child nodes
  void* (*allocator_)(size_t);          // Memory allocator

 public:
  typedef uintptr_t Number;

  explicit TCMalloc_PageMap2(void* (*allocator)(size_t)) {
    allocator_ = allocator;
    memset(root_, 0, sizeof(root_));
  }

  ALWAYS_INLINE
  void* get(Number k) const {
    const Number i1 = k >> LEAF_BITS;
    const Number i2 = k & (LEAF_LENGTH-1);
    if ((k >> BITS) > 0 || root_[i1] == nullptr) {
      return nullptr;
    }
    return root_[i1]->values[i2];
  }

  void set(Number k, void* v) {
    const Number i1 = k >> LEAF_BITS;
    const Number i2 = k & (LEAF_LENGTH-1);
    ASSERT(i1 < ROOT_LENGTH);
    root_[i1]->values[i2] = v;
  }

  bool Ensure(Number start, size_t n) {
    for (Number key = start; key <= start + n - 1; ) {
      const Number i1 = key >> LEAF_BITS;

      // Check for overflow
      if (i1 >= ROOT_LENGTH)
        return false;

      // Make 2nd level node if necessary
      if (root_[i1] == nullptr) {
        Leaf* leaf = reinterpret_cast((*allocator_)(sizeof(Leaf)));
        if (leaf == nullptr) return false;
        memset(leaf, 0, sizeof(*leaf));
        root_[i1] = leaf;
      }

      // Advance key past whatever is covered by this leaf node
      key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
    }
    return true;
  }

  void PreallocateMoreMemory() {
    // Allocate enough to keep track of all possible pages
    if (BITS < 20) {
      Ensure(0, Number(1) << BITS);
    }
  }

  void* Next(Number k) const {
    while (k < (Number(1) << BITS)) {
      const Number i1 = k >> LEAF_BITS;
      Leaf* leaf = root_[i1];
      if (leaf != nullptr) {
        // Scan forward in leaf
        for (Number i2 = k & (LEAF_LENGTH - 1); i2 < LEAF_LENGTH; i2++) {
          if (leaf->values[i2] != nullptr) {
            return leaf->values[i2];
          }
        }
      }
      // Skip to next top-level entry
      k = (i1 + 1) << LEAF_BITS;
    }
    return nullptr;
  }
};

// Three-level radix tree
template 
class TCMalloc_PageMap3 {
 private:
  // How many bits should we consume at each interior level
  static const int INTERIOR_BITS = (BITS + 2) / 3; // Round-up
  static const int INTERIOR_LENGTH = 1 << INTERIOR_BITS;

  // How many bits should we consume at leaf level
  static const int LEAF_BITS = BITS - 2*INTERIOR_BITS;
  static const int LEAF_LENGTH = 1 << LEAF_BITS;

  // Interior node
  struct Node {
    Node* ptrs[INTERIOR_LENGTH];
  };

  // Leaf node
  struct Leaf {
    void* values[LEAF_LENGTH];
  };

  Node  root_;                          // Root of radix tree
  void* (*allocator_)(size_t);          // Memory allocator

  Node* NewNode() {
    Node* result = reinterpret_cast((*allocator_)(sizeof(Node)));
    if (result != nullptr) {
      memset(result, 0, sizeof(*result));
    }
    return result;
  }

 public:
  typedef uintptr_t Number;

  explicit TCMalloc_PageMap3(void* (*allocator)(size_t)) {
    allocator_ = allocator;
    memset(&root_, 0, sizeof(root_));
  }

  ALWAYS_INLINE
  void* get(Number k) const {
    const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
    const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
    const Number i3 = k & (LEAF_LENGTH-1);
    if ((k >> BITS) > 0 ||
        root_.ptrs[i1] == nullptr || root_.ptrs[i1]->ptrs[i2] == nullptr) {
      return nullptr;
    }
    return reinterpret_cast(root_.ptrs[i1]->ptrs[i2])->values[i3];
  }

  void set(Number k, void* v) {
    ASSERT(k >> BITS == 0);
    const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
    const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
    const Number i3 = k & (LEAF_LENGTH-1);
    reinterpret_cast(root_.ptrs[i1]->ptrs[i2])->values[i3] = v;
  }

  bool Ensure(Number start, size_t n) {
    for (Number key = start; key <= start + n - 1; ) {
      const Number i1 = key >> (LEAF_BITS + INTERIOR_BITS);
      const Number i2 = (key >> LEAF_BITS) & (INTERIOR_LENGTH-1);

      // Check for overflow
      if (i1 >= INTERIOR_LENGTH || i2 >= INTERIOR_LENGTH)
        return false;

      // Make 2nd level node if necessary
      if (root_.ptrs[i1] == nullptr) {
        Node* n = NewNode();
        if (n == nullptr) return false;
        root_.ptrs[i1] = n;
      }

      // Make leaf node if necessary
      if (root_.ptrs[i1]->ptrs[i2] == nullptr) {
        Leaf* leaf = reinterpret_cast((*allocator_)(sizeof(Leaf)));
        if (leaf == nullptr) return false;
        memset(leaf, 0, sizeof(*leaf));
        root_.ptrs[i1]->ptrs[i2] = reinterpret_cast(leaf);
      }

      // Advance key past whatever is covered by this leaf node
      key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
    }
    return true;
  }

  void PreallocateMoreMemory() {
  }

  void* Next(Number k) const {
    while (k < (Number(1) << BITS)) {
      const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
      const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
      if (root_.ptrs[i1] == nullptr) {
        // Advance to next top-level entry
        k = (i1 + 1) << (LEAF_BITS + INTERIOR_BITS);
      } else {
        Leaf* leaf = reinterpret_cast(root_.ptrs[i1]->ptrs[i2]);
        if (leaf != nullptr) {
          for (Number i3 = (k & (LEAF_LENGTH-1)); i3 < LEAF_LENGTH; i3++) {
            if (leaf->values[i3] != nullptr) {
              return leaf->values[i3];
            }
          }
        }
        // Advance to next interior entry
        k = ((k >> LEAF_BITS) + 1) << LEAF_BITS;
      }
    }
    return nullptr;
  }
};

#endif  // TCMALLOC_PAGEMAP_H_
gperftools-gperftools-2.18/src/profile-handler.cc000066400000000000000000000450451513545575200222070ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//         Nabeel Mian
//
// Implements management of profile timers and the corresponding signal handler.

#include "config.h"
#include "profile-handler.h"

#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))

#include 
#include 
#include 

#include 

#if HAVE_LINUX_SIGEV_THREAD_ID
#include 
// for timer_{create,settime} and associated typedefs & constants
#include 
// for sigevent
#include 
// for SYS_gettid
#include 
#endif

#include "base/googleinit.h"
#include "base/logging.h"
#include "base/spinlock.h"
#include "base/threading.h"

// Some Linux systems don't have sigev_notify_thread_id defined in
// signal.h (despite having SIGEV_THREAD_ID defined) and also lack
// working linux/signal.h. So lets workaround. Note, we know that at
// least on Linux sigev_notify_thread_id is macro.
//
// See https://sourceware.org/bugzilla/show_bug.cgi?id=27417 and
// https://bugzilla.kernel.org/show_bug.cgi?id=200081
//
#if __linux__ && HAVE_LINUX_SIGEV_THREAD_ID && !defined(sigev_notify_thread_id)
#define sigev_notify_thread_id _sigev_un._tid
#endif

// This structure is used by ProfileHandlerRegisterCallback and
// ProfileHandlerUnregisterCallback as a handle to a registered callback.
struct ProfileHandlerToken {
  // Sets the callback and associated arg.
  ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg)
      : callback(cb),
        callback_arg(cb_arg) {
  }

  // Callback function to be invoked on receiving a profile timer interrupt.
  ProfileHandlerCallback callback;
  // Argument for the callback function.
  void* callback_arg;
};

// Blocks a signal from being delivered to the current thread while the object
// is alive. Unblocks it upon destruction.
class ScopedSignalBlocker {
 public:
  ScopedSignalBlocker(int signo) {
    sigemptyset(&sig_set_);
    sigaddset(&sig_set_, signo);
    RAW_CHECK(sigprocmask(SIG_BLOCK, &sig_set_, nullptr) == 0,
              "sigprocmask (block)");
  }
  ~ScopedSignalBlocker() {
    RAW_CHECK(sigprocmask(SIG_UNBLOCK, &sig_set_, nullptr) == 0,
              "sigprocmask (unblock)");
  }

 private:
  sigset_t sig_set_;
};

// This class manages profile timers and associated signal handler. This is a
// a singleton.
class ProfileHandler {
 public:
  // Registers the current thread with the profile handler.
  void RegisterThread();

  // Registers a callback routine to receive profile timer ticks. The returned
  // token is to be used when unregistering this callback and must not be
  // deleted by the caller.
  ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback,
                                        void* callback_arg);

  // Unregisters a previously registered callback. Expects the token returned
  // by the corresponding RegisterCallback routine.
  void UnregisterCallback(ProfileHandlerToken* token)
      NO_THREAD_SAFETY_ANALYSIS;

  // Unregisters all the callbacks and stops the timer(s).
  void Reset();

  // Gets the current state of profile handler.
  void GetState(ProfileHandlerState* state);

  // Initializes and returns the ProfileHandler singleton.
  static ProfileHandler* Instance();

 private:
  ProfileHandler();
  ~ProfileHandler();

  // Largest allowed frequency.
  static const int32_t kMaxFrequency = 4000;
  // Default frequency.
  static const int32_t kDefaultFrequency = 100;

  // ProfileHandler singleton.
  static ProfileHandler* instance_;

  // Initializes the ProfileHandler singleton via GoogleOnceInit.
  static void Init();

  // Timer state as configured previously.
  bool timer_running_;

  // The number of profiling signal interrupts received.
  int64_t interrupts_ GUARDED_BY(signal_lock_);

  // Profiling signal interrupt frequency, read-only after construction.
  int32_t frequency_;

  // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM).
  // Translated into an equivalent choice of clock if per_thread_timer_enabled_
  // is true.
  int timer_type_;

  // Signal number for timer signal.
  int signal_number_;

  // Counts the number of callbacks registered.
  int32_t callback_count_ GUARDED_BY(control_lock_);

  // Is profiling allowed at all?
  bool allowed_;

  // Must be false if HAVE_LINUX_SIGEV_THREAD_ID is not defined.
  bool per_thread_timer_enabled_;

#if HAVE_LINUX_SIGEV_THREAD_ID
  // this is used to destroy per-thread profiling timers on thread
  // termination
  tcmalloc::TlsKey thread_timer_key;
#endif

  // This lock serializes the registration of threads and protects the
  // callbacks_ list below.
  // Locking order:
  // In the context of a signal handler, acquire signal_lock_ to walk the
  // callback list. Otherwise, acquire control_lock_, disable the signal
  // handler and then acquire signal_lock_.
  SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_);
  SpinLock signal_lock_;

  // Holds the list of registered callbacks. We expect the list to be pretty
  // small. Currently, the cpu profiler (base/profiler) and thread module
  // (base/thread.h) are the only two components registering callbacks.
  // Following are the locking requirements for callbacks_:
  // For read-write access outside the SIGPROF handler:
  //  - Acquire control_lock_
  //  - Disable SIGPROF handler.
  //  - Acquire signal_lock_
  //  - Nothing that takes ~any other lock can be nested
  //    here. E.g. including malloc. Otherwise deadlock is possible.
  // For read-only access in the context of SIGPROF handler
  // (Read-write access is *not allowed* in the SIGPROF handler)
  //  - Acquire signal_lock_
  // For read-only access outside SIGPROF handler:
  //  - Acquire control_lock_
  typedef std::list CallbackList;
  typedef CallbackList::iterator CallbackIterator;
  CallbackList callbacks_ GUARDED_BY(signal_lock_);

  // Starts or stops the interval timer.
  // Will ignore any requests to enable or disable when
  // per_thread_timer_enabled_ is true.
  void UpdateTimer(bool enable) EXCLUSIVE_LOCKS_REQUIRED(control_lock_);

  // Returns true if the handler is not being used by something else.
  // This checks the kernel's signal handler table.
  bool IsSignalHandlerAvailable();

  // Signal handler. Iterates over and calls all the registered callbacks.
  static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext);

  DISALLOW_COPY_AND_ASSIGN(ProfileHandler);
};

ProfileHandler* ProfileHandler::instance_;

const int32_t ProfileHandler::kMaxFrequency;
const int32_t ProfileHandler::kDefaultFrequency;

// If we are LD_PRELOAD-ed against a non-pthreads app, then these functions
// won't be defined.  We declare them here, for that case (with weak linkage)
// which will cause the non-definition to resolve to nullptr.  We can then check
// for nullptr or not in Instance.
extern "C" {
#if HAVE_LINUX_SIGEV_THREAD_ID
int timer_create(clockid_t clockid, struct sigevent* evp,
                 timer_t* timerid) ATTRIBUTE_WEAK;
int timer_delete(timer_t timerid) ATTRIBUTE_WEAK;
int timer_settime(timer_t timerid, int flags, const struct itimerspec* value,
                  struct itimerspec* ovalue) ATTRIBUTE_WEAK;
#endif
}

#if HAVE_LINUX_SIGEV_THREAD_ID

struct timer_id_holder {
  timer_t timerid;
  timer_id_holder(timer_t _timerid) : timerid(_timerid) {}
};

extern "C" {
  static void ThreadTimerDestructor(void *arg) {
    if (!arg) {
      return;
    }
    timer_id_holder *holder = static_cast(arg);
    timer_delete(holder->timerid);
    delete holder;
  }
}

static void CreateThreadTimerKey(tcmalloc::TlsKey *pkey) {
  int rv = tcmalloc::CreateTlsKey(pkey, ThreadTimerDestructor);
  if (rv) {
    RAW_LOG(FATAL, "aborting due to tcmalloc::CreateTlsKey error: %s", strerror(rv));
  }
}

static void StartLinuxThreadTimer(int timer_type, int signal_number,
                                  int32_t frequency, tcmalloc::TlsKey timer_key) {
  int rv;
  struct sigevent sevp;
  timer_t timerid;
  struct itimerspec its;
  memset(&sevp, 0, sizeof(sevp));
  sevp.sigev_notify = SIGEV_THREAD_ID;
  sevp.sigev_notify_thread_id = syscall(SYS_gettid);
  sevp.sigev_signo = signal_number;
  clockid_t clock = CLOCK_THREAD_CPUTIME_ID;
  if (timer_type == ITIMER_REAL) {
    clock = CLOCK_MONOTONIC;
  }
  rv = timer_create(clock, &sevp, &timerid);
  if (rv) {
    RAW_LOG(FATAL, "aborting due to timer_create error: %s", strerror(errno));
  }

  timer_id_holder *holder = new timer_id_holder(timerid);
  rv = tcmalloc::SetTlsValue(timer_key, holder);
  if (rv) {
    RAW_LOG(FATAL, "aborting due to tcmalloc::SetTlsValue error: %s", strerror(rv));
  }

  its.it_interval.tv_sec = 0;
  its.it_interval.tv_nsec = 1000000000 / frequency;
  its.it_value = its.it_interval;
  rv = timer_settime(timerid, 0, &its, 0);
  if (rv) {
    RAW_LOG(FATAL, "aborting due to timer_settime error: %s", strerror(errno));
  }
}
#endif

void ProfileHandler::Init() {
  instance_ = new ProfileHandler();
}


ProfileHandler* ProfileHandler::Instance() {
  static tcmalloc::TrivialOnce once;

  once.RunOnce(&Init);

  assert(instance_ != nullptr);

  return instance_;
}

ProfileHandler::ProfileHandler()
    : timer_running_(false),
      interrupts_(0),
      callback_count_(0),
      allowed_(true),
      per_thread_timer_enabled_(false) {
  SpinLockHolder cl(&control_lock_);

  timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
  signal_number_ = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);

  // Get frequency of interrupts (if specified)
  char junk;
  const char* fr = getenv("CPUPROFILE_FREQUENCY");
  if (fr != nullptr && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) &&
      (frequency_ > 0)) {
    // Limit to kMaxFrequency
    frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_;
  } else {
    frequency_ = kDefaultFrequency;
  }

  if (!allowed_) {
    return;
  }

#if HAVE_LINUX_SIGEV_THREAD_ID
  // Do this early because we might be overriding signal number.

  const char *per_thread = getenv("CPUPROFILE_PER_THREAD_TIMERS");
  const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");

  if (per_thread || signal_number) {
    if (timer_create) {
      CreateThreadTimerKey(&thread_timer_key);
      per_thread_timer_enabled_ = true;
      // Override signal number if requested.
      if (signal_number) {
        signal_number_ = strtol(signal_number, nullptr, 0);
      }
    } else {
      RAW_LOG(INFO,
              "Ignoring CPUPROFILE_PER_THREAD_TIMERS and\n"
              " CPUPROFILE_TIMER_SIGNAL due to lack of timer_create().\n"
              " Preload or link to librt.so for this to work");
    }
  }
#endif

  // If something else is using the signal handler,
  // assume it has priority over us and stop.
  if (!IsSignalHandlerAvailable()) {
    RAW_LOG(INFO, "Disabling profiler because signal %d handler is already in use.",
            signal_number_);
    allowed_ = false;
    return;
  }

  // Install the signal handler.
  struct sigaction sa;
  sa.sa_sigaction = SignalHandler;
  sa.sa_flags = SA_RESTART | SA_SIGINFO;
  sigemptyset(&sa.sa_mask);
  RAW_CHECK(sigaction(signal_number_, &sa, nullptr) == 0, "sigprof (enable)");
}

ProfileHandler::~ProfileHandler() {
  Reset();
#if HAVE_LINUX_SIGEV_THREAD_ID
  if (per_thread_timer_enabled_) {
    pthread_key_delete(thread_timer_key);
  }
#endif
}

void ProfileHandler::RegisterThread() {
  SpinLockHolder cl(&control_lock_);

  if (!allowed_) {
    return;
  }

  // Record the thread identifier and start the timer if profiling is on.
#if HAVE_LINUX_SIGEV_THREAD_ID
  if (per_thread_timer_enabled_) {
    StartLinuxThreadTimer(timer_type_, signal_number_, frequency_,
                          thread_timer_key);
    return;
  }
#endif
  UpdateTimer(callback_count_ > 0);
}

ProfileHandlerToken* ProfileHandler::RegisterCallback(
    ProfileHandlerCallback callback, void* callback_arg) {

  ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg);
  CallbackList copy;
  copy.push_back(token);

  SpinLockHolder cl(&control_lock_);
  {
    ScopedSignalBlocker block(signal_number_);
    SpinLockHolder sl(&signal_lock_);
    callbacks_.splice(callbacks_.end(), copy);
  }

  ++callback_count_;
  UpdateTimer(true);
  return token;
}

void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) {
  SpinLockHolder cl(&control_lock_);
  RAW_CHECK(callback_count_ > 0, "Invalid callback count");

  CallbackList copy;
  bool found = false;
  for (ProfileHandlerToken* callback_token : callbacks_) {
    if (callback_token == token) {
      found = true;
    } else {
      copy.push_back(callback_token);
    }
  }

  if (!found) {
    RAW_LOG(FATAL, "Invalid token");
  }

  {
    ScopedSignalBlocker block(signal_number_);
    SpinLockHolder sl(&signal_lock_);
    // Replace callback list holding signal lock. We cannot call
    // pretty much anything that takes locks. Including malloc
    // locks. So we only swap here and cleanup later.
    using std::swap;
    swap(copy, callbacks_);
  }
  // copy gets deleted after signal_lock_ is dropped

  --callback_count_;
  if (callback_count_ == 0) {
    UpdateTimer(false);
  }
  delete token;
}

void ProfileHandler::Reset() {
  SpinLockHolder cl(&control_lock_);
  CallbackList copy;
  {
    ScopedSignalBlocker block(signal_number_);
    SpinLockHolder sl(&signal_lock_);
    // Only do swap under this critical lock.
    using std::swap;
    swap(copy, callbacks_);
  }
  for (ProfileHandlerToken* token : copy) {
    delete token;
  }
  callback_count_ = 0;
  UpdateTimer(false);
  // copy gets deleted here
}

void ProfileHandler::GetState(ProfileHandlerState* state) {
  SpinLockHolder cl(&control_lock_);
  {
    ScopedSignalBlocker block(signal_number_);
    SpinLockHolder sl(&signal_lock_);  // Protects interrupts_.
    state->interrupts = interrupts_;
  }
  state->frequency = frequency_;
  state->callback_count = callback_count_;
  state->allowed = allowed_;
}

void ProfileHandler::UpdateTimer(bool enable) {
  if (per_thread_timer_enabled_) {
    // Ignore any attempts to disable it because that's not supported, and it's
    // always enabled so enabling is always a NOP.
    return;
  }

  if (enable == timer_running_) {
    return;
  }
  timer_running_ = enable;

  struct itimerval timer;
  static const int kMillion = 1000000;
  int interval_usec = enable ? kMillion / frequency_ : 0;
  timer.it_interval.tv_sec = interval_usec / kMillion;
  timer.it_interval.tv_usec = interval_usec % kMillion;
  timer.it_value = timer.it_interval;
  setitimer(timer_type_, &timer, 0);
}

bool ProfileHandler::IsSignalHandlerAvailable() {
  struct sigaction sa;
  RAW_CHECK(sigaction(signal_number_, nullptr, &sa) == 0, "is-signal-handler avail");

  // We only take over the handler if the current one is unset.
  // It must be SIG_IGN or SIG_DFL, not some other function.
  // SIG_IGN must be allowed because when profiling is allowed but
  // not actively in use, this code keeps the handler set to SIG_IGN.
  // That setting will be inherited across fork+exec.  In order for
  // any child to be able to use profiling, SIG_IGN must be treated
  // as available.
  return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL;
}

void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) {
  int saved_errno = errno;
  // At this moment, instance_ must be initialized because the handler is
  // enabled in RegisterThread or RegisterCallback only after
  // ProfileHandler::Instance runs.
  ProfileHandler* instance = instance_;
  RAW_CHECK(instance != nullptr, "ProfileHandler is not initialized");
  {
    SpinLockHolder sl(&instance->signal_lock_);
    ++instance->interrupts_;
    for (CallbackIterator it = instance->callbacks_.begin();
         it != instance->callbacks_.end();
         ++it) {
      (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg);
    }
  }
  errno = saved_errno;
}

// This module initializer registers the main thread, so it must be
// executed in the context of the main thread.
REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread());

void ProfileHandlerRegisterThread() {
  ProfileHandler::Instance()->RegisterThread();
}

ProfileHandlerToken* ProfileHandlerRegisterCallback(
    ProfileHandlerCallback callback, void* callback_arg) {
  return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg);
}

void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
  ProfileHandler::Instance()->UnregisterCallback(token);
}

void ProfileHandlerReset() {
  return ProfileHandler::Instance()->Reset();
}

void ProfileHandlerGetState(ProfileHandlerState* state) {
  ProfileHandler::Instance()->GetState(state);
}

#else  // OS_CYGWIN

// ITIMER_PROF doesn't work under cygwin.  ITIMER_REAL is available, but doesn't
// work as well for profiling, and also interferes with alarm().  Because of
// these issues, unless a specific need is identified, profiler support is
// disabled under Cygwin.
void ProfileHandlerRegisterThread() {
}

ProfileHandlerToken* ProfileHandlerRegisterCallback(
    ProfileHandlerCallback callback, void* callback_arg) {
  return nullptr;
}

void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
}

void ProfileHandlerReset() {
}

void ProfileHandlerGetState(ProfileHandlerState* state) {
}

#endif  // OS_CYGWIN
gperftools-gperftools-2.18/src/profile-handler.h000066400000000000000000000137451513545575200220530ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Nabeel Mian
 *
 * This module manages the cpu profile timers and the associated interrupt
 * handler. When enabled, all threads in the program are profiled.
 *
 * Any component interested in receiving a profile timer interrupt can do so by
 * registering a callback. All registered callbacks must be async-signal-safe.
 *
 * Note: This module requires the sole ownership of the configured timer and
 * signal. The timer defaults to ITIMER_PROF, can be changed to ITIMER_REAL by
 * the environment variable CPUPROFILE_REALTIME, or is changed to a POSIX timer
 * with CPUPROFILE_PER_THREAD_TIMERS. The signal defaults to SIGPROF/SIGALRM to
 * match the choice of timer and can be set to an arbitrary value using
 * CPUPROFILE_TIMER_SIGNAL with CPUPROFILE_PER_THREAD_TIMERS.
 */

#ifndef BASE_PROFILE_HANDLER_H_
#define BASE_PROFILE_HANDLER_H_

#include "config.h"

#include  // IWYU pragma: keep
#include 

/* Forward declaration. */
struct ProfileHandlerToken;

/*
 * Callback function to be used with ProfilefHandlerRegisterCallback. This
 * function will be called in the context of SIGPROF signal handler and must
 * be async-signal-safe. The first three arguments are the values provided by
 * the SIGPROF signal handler. We use void* to avoid using ucontext_t on
 * non-POSIX systems.
 *
 * Requirements:
 * - Callback must be async-signal-safe.
 * - None of the functions in ProfileHandler are async-signal-safe. Therefore,
 *   callback function *must* not call any of the ProfileHandler functions.
 * - Callback is not required to be re-entrant. At most one instance of
 *   callback can run at a time.
 *
 * Notes:
 * - The SIGPROF signal handler saves and restores errno, so the callback
 *   doesn't need to.
 * - Callback code *must* not acquire lock(s) to serialize access to data shared
 *   with the code outside the signal handler (callback must be
 *   async-signal-safe). If such a serialization is needed, follow the model
 *   used by profiler.cc:
 *
 *   When code other than the signal handler modifies the shared data it must:
 *   - Acquire lock.
 *   - Unregister the callback with the ProfileHandler.
 *   - Modify shared data.
 *   - Re-register the callback.
 *   - Release lock.
 *   and the callback code gets a lockless, read-write access to the data.
 */
typedef void (*ProfileHandlerCallback)(int sig, siginfo_t* sig_info,
                                       void* ucontext, void* callback_arg);

/*
 * Registers a new thread with profile handler and should be called only once
 * per thread. The main thread is registered at program startup. This routine
 * is called by the Thread module in google3/thread whenever a new thread is
 * created. This function is not async-signal-safe.
 */
void ProfileHandlerRegisterThread();

/*
 * Registers a callback routine. This callback function will be called in the
 * context of SIGPROF handler, so must be async-signal-safe. The returned token
 * is to be used when unregistering this callback via
 * ProfileHandlerUnregisterCallback. Registering the first callback enables
 * the SIGPROF signal handler. Caller must not free the returned token. This
 * function is not async-signal-safe.
 */
ProfileHandlerToken* ProfileHandlerRegisterCallback(
    ProfileHandlerCallback callback, void* callback_arg);

/*
 * Unregisters a previously registered callback. Expects the token returned
 * by the corresponding ProfileHandlerRegisterCallback and asserts that the
 * passed token is valid. Unregistering the last callback disables the SIGPROF
 * signal handler. It waits for the currently running callback to
 * complete before returning. This function is not async-signal-safe.
 */
void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token);

/*
 * FOR TESTING ONLY
 * Unregisters all the callbacks, stops the timers (if shared) and disables the
 * SIGPROF handler. All the threads, including the main thread, need to be
 * re-registered after this call. This function is not async-signal-safe.
 */
void ProfileHandlerReset();

/*
 * Stores profile handler's current state. This function is not
 * async-signal-safe.
 */
struct ProfileHandlerState {
  int32_t frequency;  /* Profiling frequency */
  int32_t callback_count;  /* Number of callbacks registered */
  int64_t interrupts;  /* Number of interrupts received */
  bool allowed; /* Profiling is allowed */
};
void ProfileHandlerGetState(struct ProfileHandlerState* state);

#endif  /* BASE_PROFILE_HANDLER_H_ */
gperftools-gperftools-2.18/src/profiledata.cc000066400000000000000000000213361513545575200214230ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Sanjay Ghemawat
//         Chris Demetriou (refactoring)
//
// Collect profiling data.

#include 
#include 
#include 
#include 
#include 
#ifdef HAVE_UNISTD_H
#include 
#endif
#include 
#include 
#include 

#include "profiledata.h"

#include "base/logging.h"
#include "base/proc_maps_iterator.h"

// All of these are initialized in profiledata.h.
const int ProfileData::kMaxStackDepth;
const int ProfileData::kAssociativity;
const int ProfileData::kBuckets;
const int ProfileData::kBufferLength;

ProfileData::Options::Options()
    : frequency_(1) {
}

// This function is safe to call from asynchronous signals (but is not
// re-entrant).  However, that's not part of its public interface.
void ProfileData::Evict(const Entry& entry) {
  const int d = entry.depth;
  const int nslots = d + 2;     // Number of slots needed in eviction buffer
  if (num_evicted_ + nslots > kBufferLength) {
    FlushEvicted();
    assert(num_evicted_ == 0);
    assert(nslots <= kBufferLength);
  }
  evict_[num_evicted_++] = entry.count;
  evict_[num_evicted_++] = d;
  memcpy(&evict_[num_evicted_], entry.stack, d * sizeof(Slot));
  num_evicted_ += d;
}

ProfileData::ProfileData()
    : hash_(0),
      evict_(0),
      num_evicted_(0),
      out_(-1),
      count_(0),
      evictions_(0),
      total_bytes_(0),
      fname_(0),
      start_time_(0) {
}

bool ProfileData::Start(const char* fname,
                        const ProfileData::Options& options) {
  if (enabled()) {
    return false;
  }

  // Open output file and initialize various data structures
  int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0666);
  if (fd < 0) {
    // Can't open outfile for write
    return false;
  }

  start_time_ = time(nullptr);
  fname_ = strdup(fname);

  // Reset counters
  num_evicted_ = 0;
  count_       = 0;
  evictions_   = 0;
  total_bytes_ = 0;

  hash_ = new Bucket[kBuckets];
  evict_ = new Slot[kBufferLength];
  memset(hash_, 0, sizeof(hash_[0]) * kBuckets);

  // Record special entries
  evict_[num_evicted_++] = 0;                     // count for header
  evict_[num_evicted_++] = 3;                     // depth for header
  evict_[num_evicted_++] = 0;                     // Version number
  CHECK_NE(0, options.frequency());
  int period = 1000000 / options.frequency();
  evict_[num_evicted_++] = period;                // Period (microseconds)
  evict_[num_evicted_++] = 0;                     // Padding

  out_ = fd;

  return true;
}

ProfileData::~ProfileData() {
  Stop();
}

// Dump /proc/maps data to fd.  Copied from heap-profile-table.cc.
#define NO_INTR(fn)  do {} while ((fn) < 0 && errno == EINTR)

static void FDWrite(int fd, const char* buf, size_t len) {
  while (len > 0) {
    ssize_t r;
    NO_INTR(r = write(fd, buf, len));
    RAW_CHECK(r >= 0, "write failed");
    buf += r;
    len -= r;
  }
}

void ProfileData::Stop() {
  if (!enabled()) {
    return;
  }

  // Move data from hash table to eviction buffer
  for (int b = 0; b < kBuckets; b++) {
    Bucket* bucket = &hash_[b];
    for (int a = 0; a < kAssociativity; a++) {
      if (bucket->entry[a].count > 0) {
        Evict(bucket->entry[a]);
      }
    }
  }

  if (num_evicted_ + 3 > kBufferLength) {
    // Ensure there is enough room for end of data marker
    FlushEvicted();
  }

  // Write end of data marker
  evict_[num_evicted_++] = 0;         // count
  evict_[num_evicted_++] = 1;         // depth
  evict_[num_evicted_++] = 0;         // end of data marker
  FlushEvicted();

  // Dump "/proc/self/maps" so we get list of mapped shared libraries
  tcmalloc::SaveProcSelfMapsToRawFD(static_cast(out_));

  Reset();
  fprintf(stderr, "PROFILE: interrupts/evictions/bytes = %d/%d/%zu\n",
          count_, evictions_, total_bytes_);
}

void ProfileData::Reset() {
  if (!enabled()) {
    return;
  }

  // Don't reset count_, evictions_, or total_bytes_ here.  They're used
  // by Stop to print information about the profile after reset, and are
  // cleared by Start when starting a new profile.
  close(out_);
  delete[] hash_;
  hash_ = 0;
  delete[] evict_;
  evict_ = 0;
  num_evicted_ = 0;
  free(fname_);
  fname_ = 0;
  start_time_ = 0;

  out_ = -1;
}

// This function is safe to call from asynchronous signals (but is not
// re-entrant).  However, that's not part of its public interface.
void ProfileData::GetCurrentState(State* state) const {
  if (enabled()) {
    state->enabled = true;
    state->start_time = start_time_;
    state->samples_gathered = count_;
    int buf_size = sizeof(state->profile_name);
    strncpy(state->profile_name, fname_ ? fname_ : "", buf_size);
    state->profile_name[buf_size-1] = '\0';
  } else {
    state->enabled = false;
    state->start_time = 0;
    state->samples_gathered = 0;
    state->profile_name[0] = '\0';
  }
}

// This function is safe to call from asynchronous signals (but is not
// re-entrant).  However, that's not part of its public interface.
void ProfileData::FlushTable() {
  if (!enabled()) {
    return;
  }

  // Move data from hash table to eviction buffer
  for (int b = 0; b < kBuckets; b++) {
    Bucket* bucket = &hash_[b];
    for (int a = 0; a < kAssociativity; a++) {
      if (bucket->entry[a].count > 0) {
        Evict(bucket->entry[a]);
        bucket->entry[a].depth = 0;
        bucket->entry[a].count = 0;
      }
    }
  }

  // Write out all pending data
  FlushEvicted();
}

void ProfileData::Add(int depth, const void* const* stack) {
  if (!enabled()) {
    return;
  }

  if (depth > kMaxStackDepth) depth = kMaxStackDepth;
  RAW_CHECK(depth > 0, "ProfileData::Add depth <= 0");

  // Make hash-value
  Slot h = 0;
  for (int i = 0; i < depth; i++) {
    Slot slot = reinterpret_cast(stack[i]);
    h = (h << 8) | (h >> (8*(sizeof(h)-1)));
    h += (slot * 31) + (slot * 7) + (slot * 3);
  }

  count_++;

  // See if table already has an entry for this trace
  bool done = false;
  Bucket* bucket = &hash_[h % kBuckets];
  for (int a = 0; a < kAssociativity; a++) {
    Entry* e = &bucket->entry[a];
    if (e->depth == depth) {
      bool match = true;
      for (int i = 0; i < depth; i++) {
        if (e->stack[i] != reinterpret_cast(stack[i])) {
          match = false;
          break;
        }
      }
      if (match) {
        e->count++;
        done = true;
        break;
      }
    }
  }

  if (!done) {
    // Evict entry with smallest count
    Entry* e = &bucket->entry[0];
    for (int a = 1; a < kAssociativity; a++) {
      if (bucket->entry[a].count < e->count) {
        e = &bucket->entry[a];
      }
    }
    if (e->count > 0) {
      evictions_++;
      Evict(*e);
    }

    // Use the newly evicted entry
    e->depth = depth;
    e->count = 1;
    for (int i = 0; i < depth; i++) {
      e->stack[i] = reinterpret_cast(stack[i]);
    }
  }
}

// This function is safe to call from asynchronous signals (but is not
// re-entrant).  However, that's not part of its public interface.
void ProfileData::FlushEvicted() {
  if (num_evicted_ > 0) {
    const char* buf = reinterpret_cast(evict_);
    size_t bytes = sizeof(evict_[0]) * num_evicted_;
    total_bytes_ += bytes;
    FDWrite(out_, buf, bytes);
  }
  num_evicted_ = 0;
}
gperftools-gperftools-2.18/src/profiledata.h000066400000000000000000000147421513545575200212700ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Sanjay Ghemawat
//         Chris Demetriou (refactoring)
//
// Collect profiling data.
//
// The profile data file format is documented in
// docs/cpuprofile-fileformat.html


#ifndef BASE_PROFILEDATA_H_
#define BASE_PROFILEDATA_H_

#include 
#include    // for time_t
#include 
#include "base/basictypes.h"

// A class that accumulates profile samples and writes them to a file.
//
// Each sample contains a stack trace and a count.  Memory usage is
// reduced by combining profile samples that have the same stack trace
// by adding up the associated counts.
//
// Profile data is accumulated in a bounded amount of memory, and will
// flushed to a file as necessary to stay within the memory limit.
//
// Use of this class assumes external synchronization.  The exact
// requirements of that synchronization are that:
//
//  - 'Add' may be called from asynchronous signals, but is not
//    re-entrant.
//
//  - None of 'Start', 'Stop', 'Reset', 'Flush', and 'Add' may be
//    called at the same time.
//
//  - 'Start', 'Stop', or 'Reset' should not be called while 'Enabled'
//     or 'GetCurrent' are running, and vice versa.
//
// A profiler which uses asyncronous signals to add samples will
// typically use two locks to protect this data structure:
//
//  - A SpinLock which is held over all calls except for the 'Add'
//    call made from the signal handler.
//
//  - A SpinLock which is held over calls to 'Start', 'Stop', 'Reset',
//    'Flush', and 'Add'.  (This SpinLock should be acquired after
//    the first SpinLock in all cases where both are needed.)
class ProfileData {
 public:
  struct State {
    bool     enabled;             // Is profiling currently enabled?
    time_t   start_time;          // If enabled, when was profiling started?
    char     profile_name[1024];  // Name of file being written, or '\0'
    int      samples_gathered;    // Number of samples gathered to far (or 0)
  };

  class Options {
   public:
    Options();

    // Get and set the sample frequency.
    int frequency() const {
      return frequency_;
    }
    void set_frequency(int frequency) {
      frequency_ = frequency;
    }

   private:
    int      frequency_;                  // Sample frequency.
  };

  static const int kMaxStackDepth = 254;  // Max stack depth stored in profile

  ProfileData();
  ~ProfileData();

  // If data collection is not already enabled start to collect data
  // into fname.  Parameters related to this profiling run are specified
  // by 'options'.
  //
  // Returns true if data collection could be started, otherwise (if an
  // error occurred or if data collection was already enabled) returns
  // false.
  bool Start(const char *fname, const Options& options);

  // If data collection is enabled, stop data collection and write the
  // data to disk.
  void Stop();

  // Stop data collection without writing anything else to disk, and
  // discard any collected data.
  void Reset();

  // If data collection is enabled, record a sample with 'depth'
  // entries from 'stack'.  (depth must be > 0.)  At most
  // kMaxStackDepth stack entries will be recorded, starting with
  // stack[0].
  //
  // This function is safe to call from asynchronous signals (but is
  // not re-entrant).
  void Add(int depth, const void* const* stack);

  // If data collection is enabled, write the data to disk (and leave
  // the collector enabled).
  void FlushTable();

  // Is data collection currently enabled?
  bool enabled() const { return out_ >= 0; }

  // Get the current state of the data collector.
  void GetCurrentState(State* state) const;

 private:
  friend class CpuProfiler;

  static const int kAssociativity = 4;          // For hashtable
  static const int kBuckets = 1 << 10;          // For hashtable
  static const int kBufferLength = 1 << 18;     // For eviction buffer

  // Type of slots: each slot can be either a count, or a PC value
  typedef uintptr_t Slot;

  // Hash-table/eviction-buffer entry (a.k.a. a sample)
  struct Entry {
    Slot count;                  // Number of hits
    Slot depth;                  // Stack depth
    Slot stack[kMaxStackDepth];  // Stack contents
  };

  // Hash table bucket
  struct Bucket {
    Entry entry[kAssociativity];
  };

  Bucket*       hash_;          // hash table
  Slot*         evict_;         // evicted entries
  int           num_evicted_;   // how many evicted entries?
  int           out_;           // fd for output file.
  int           count_;         // How many samples recorded
  int           evictions_;     // How many evictions
  size_t        total_bytes_;   // How much output
  char*         fname_;         // Profile file name
  time_t        start_time_;    // Start time, or 0

  // Move 'entry' to the eviction buffer.
  void Evict(const Entry& entry);

  // Write contents of eviction buffer to disk.
  void FlushEvicted();

  DISALLOW_COPY_AND_ASSIGN(ProfileData);
};

#endif  // BASE_PROFILEDATA_H_
gperftools-gperftools-2.18/src/profiler.cc000066400000000000000000000346151513545575200207570ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//         Chris Demetriou (refactoring)
//
// Profile current program by sampling stack-trace every so often

#include "config.h"
#include "getpc.h"      // should be first to get the _GNU_SOURCE dfn
#include 
#include 
#include 
#include 
#include 
#ifdef HAVE_UNISTD_H
#include   // for getpid()
#endif
#if HAVE_SYS_UCONTEXT_H
#include 
#elif HAVE_UCONTEXT_H
#include 
#elif defined(HAVE_CYGWIN_SIGNAL_H)
#include 
typedef ucontext ucontext_t;
#else
typedef int ucontext_t;   // just to quiet the compiler, mostly
#endif
#include 
#include 
#include 
#include "base/logging.h"
#include "base/spinlock.h"
#include "base/sysinfo.h"             /* for GetUniquePathFromEnv, etc */
#include "profiledata.h"
#include "profile-handler.h"

// Collects up all profile data. This is a singleton, which is
// initialized by a constructor at startup. If no cpu profiler
// signal is specified then the profiler lifecycle is either
// manaully controlled via the API or attached to the scope of
// the singleton (program scope). Otherwise the cpu toggle is
// used to allow for user selectable control via signal generation.
// This is very useful for profiling a daemon process without
// having to start and stop the daemon or having to modify the
// source code to use the cpu profiler API.
class CpuProfiler {
 public:
  CpuProfiler();
  ~CpuProfiler();

  // Start profiler to write profile info into fname
  bool Start(const char* fname, const ProfilerOptions* options);

  // Stop profiling and write the data to disk.
  void Stop();

  // Write the data to disk (and continue profiling).
  void FlushTable();

  bool Enabled();

  void GetCurrentState(ProfilerState* state);

  static CpuProfiler instance_;

 private:
  // This lock implements the locking requirements described in the ProfileData
  // documentation, specifically:
  //
  // lock_ is held all over all collector_ method calls except for the 'Add'
  // call made from the signal handler, to protect against concurrent use of
  // collector_'s control routines. Code other than signal handler must
  // unregister the signal handler before calling any collector_ method.
  // 'Add' method in the collector is protected by a guarantee from
  // ProfileHandle that only one instance of prof_handler can run at a time.
  SpinLock      lock_;
  ProfileData   collector_;

  // Filter function and its argument, if any.  (nullptr means include all
  // samples).  Set at start, read-only while running.  Written while holding
  // lock_, read and executed in the context of SIGPROF interrupt.
  int           (*filter_)(void*);
  void*         filter_arg_;

  // Opaque token returned by the profile handler. To be used when calling
  // ProfileHandlerUnregisterCallback.
  ProfileHandlerToken* prof_handler_token_;

  // Sets up a callback to receive SIGPROF interrupt.
  void EnableHandler();

  // Disables receiving SIGPROF interrupt.
  void DisableHandler();

  // Signal handler that records the interrupted pc in the profile data.
  static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
                           void* cpu_profiler);
};

// Signal handler that is registered when a user selectable signal
// number is defined in the environment variable CPUPROFILESIGNAL.
static void CpuProfilerSwitch(int signal_number)
{
  static unsigned profile_count;
  static char base_profile_name[PATH_MAX];
  static bool started = false;

  if (base_profile_name[0] == '\0') {
    if (!GetUniquePathFromEnv("CPUPROFILE", base_profile_name)) {
      RAW_LOG(FATAL,"Cpu profiler switch is registered but no CPUPROFILE is defined");
      return;
    }
  }

  if (!started) {
    char full_profile_name[PATH_MAX + 16];

    snprintf(full_profile_name, sizeof(full_profile_name), "%s.%u",
             base_profile_name, profile_count++);

    if(!ProfilerStart(full_profile_name)) {
      RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
              full_profile_name, strerror(errno));
    }
  } else {
    ProfilerStop();
  }
  started = !started;
}

// Profile data structure singleton: Constructor will check to see if
// profiling should be enabled.  Destructor will write profile data
// out to disk.
CpuProfiler CpuProfiler::instance_;

// Initialize profiling: activated if getenv("CPUPROFILE") exists.
CpuProfiler::CpuProfiler()
    : prof_handler_token_(nullptr) {
  if (getenv("CPUPROFILE") == nullptr) {
    return;
  }

  // We don't enable profiling if setuid -- it's a security risk
#ifdef HAVE_GETEUID
  if (getuid() != geteuid()) {
    return;
  }
#endif

  char *signal_number_str = getenv("CPUPROFILESIGNAL");
  if (signal_number_str != nullptr) {
    long int signal_number = strtol(signal_number_str, nullptr, 10);
    if (signal_number >= 1 && signal_number <= 64) {
      intptr_t old_signal_handler = reinterpret_cast(signal(signal_number, CpuProfilerSwitch));
      if (old_signal_handler == 0) {
        RAW_LOG(INFO,"Using signal %d as cpu profiling switch", signal_number);
      } else {
        RAW_LOG(FATAL, "Signal %d already in use\n", signal_number);
      }
    } else {
      RAW_LOG(FATAL, "Signal number %s is invalid\n", signal_number_str);
    }
  } else {
    char fname[PATH_MAX];
    if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
      return;
    }

    if (!Start(fname, nullptr)) {
      RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
              fname, strerror(errno));
    }
  }
}

bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) {
  SpinLockHolder cl(&lock_);

  if (collector_.enabled()) {
    return false;
  }

  ProfileHandlerState prof_handler_state;
  ProfileHandlerGetState(&prof_handler_state);

  ProfileData::Options collector_options;
  collector_options.set_frequency(prof_handler_state.frequency);
  if (!collector_.Start(fname, collector_options)) {
    return false;
  }

  filter_ = nullptr;
  if (options != nullptr && options->filter_in_thread != nullptr) {
    filter_ = options->filter_in_thread;
    filter_arg_ = options->filter_in_thread_arg;
  }

  // Setup handler for SIGPROF interrupts
  EnableHandler();

  return true;
}

CpuProfiler::~CpuProfiler() {
  Stop();
}

// Stop profiling and write out any collected profile data
void CpuProfiler::Stop() {
  SpinLockHolder cl(&lock_);

  if (!collector_.enabled()) {
    return;
  }

  // Unregister prof_handler to stop receiving SIGPROF interrupts before
  // stopping the collector.
  DisableHandler();

  // DisableHandler waits for the currently running callback to complete and
  // guarantees no future invocations. It is safe to stop the collector.
  collector_.Stop();
}

void CpuProfiler::FlushTable() {
  SpinLockHolder cl(&lock_);

  if (!collector_.enabled()) {
    return;
  }

  // Unregister prof_handler to stop receiving SIGPROF interrupts before
  // flushing the profile data.
  DisableHandler();

  // DisableHandler waits for the currently running callback to complete and
  // guarantees no future invocations. It is safe to flush the profile data.
  collector_.FlushTable();

  EnableHandler();
}

bool CpuProfiler::Enabled() {
  SpinLockHolder cl(&lock_);
  return collector_.enabled();
}

void CpuProfiler::GetCurrentState(ProfilerState* state) {
  ProfileData::State collector_state;
  {
    SpinLockHolder cl(&lock_);
    collector_.GetCurrentState(&collector_state);
  }

  state->enabled = collector_state.enabled;
  state->start_time = static_cast(collector_state.start_time);
  state->samples_gathered = collector_state.samples_gathered;

  constexpr int kBufSize = sizeof(state->profile_name);
  std::string_view profile_name{collector_state.profile_name};
  memcpy(state->profile_name, profile_name.data(), std::min(kBufSize, profile_name.size() + 1));
  state->profile_name[kBufSize - 1] = '\0';

  // Note, this is "secret" and version-specific API we do for
  // profiler_unittest. It is explicitly not part of any API/ABI
  // stability guarantees.
  //
  // If there is space in profile_name left for the pointer, then we
  // append address of samples_gathered. The test uses this "ticks
  // count" as a form of clock to know how long it runs.
  if (profile_name.size() + 1 + sizeof(void*) <= kBufSize) {
    void* ptr = &collector_.count_;
    memcpy(state->profile_name + profile_name.size() + 1, &ptr, sizeof(ptr));
  }
}

void CpuProfiler::EnableHandler() {
  RAW_CHECK(prof_handler_token_ == nullptr, "SIGPROF handler already registered");
  prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this);
  RAW_CHECK(prof_handler_token_ != nullptr, "Failed to set up SIGPROF handler");
}

void CpuProfiler::DisableHandler() {
  RAW_CHECK(prof_handler_token_ != nullptr, "SIGPROF handler is not registered");
  ProfileHandlerUnregisterCallback(prof_handler_token_);
  prof_handler_token_ = nullptr;
}

// Signal handler that records the pc in the profile-data structure. We do no
// synchronization here.  profile-handler.cc guarantees that at most one
// instance of prof_handler() will run at a time. All other routines that
// access the data touched by prof_handler() disable this signal handler before
// accessing the data and therefore cannot execute concurrently with
// prof_handler().
void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
                               void* cpu_profiler) {
  CpuProfiler* instance = static_cast(cpu_profiler);

  if (instance->filter_ == nullptr ||
      (*instance->filter_)(instance->filter_arg_)) {
    void* stack[ProfileData::kMaxStackDepth];

    // Under frame-pointer-based unwinding at least on x86, the
    // top-most active routine doesn't show up as a normal frame, but
    // as the "pc" value in the signal handler context.
    stack[0] = GetPC(*reinterpret_cast(signal_ucontext));

    // We skip the top three stack trace entries (this function,
    // SignalHandler::SignalHandler and one signal handler frame)
    // since they are artifacts of profiling and should not be
    // measured.  Other profiling related frames may be removed by
    // "pprof" at analysis time.  Instead of skipping the top frames,
    // we could skip nothing, but that would increase the profile size
    // unnecessarily.
    int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
                                         3, signal_ucontext);

    void **used_stack;
    if (depth > 0 && stack[1] == stack[0]) {
      // in case of non-frame-pointer-based unwinding we will get
      // duplicate of PC in stack[1], which we don't want
      used_stack = stack + 1;
    } else {
      used_stack = stack;
      depth++;  // To account for pc value in stack[0];
    }

    instance->collector_.Add(depth, used_stack);
  }
}

#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))

extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
  ProfileHandlerRegisterThread();
}

extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
  CpuProfiler::instance_.FlushTable();
}

extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
  return CpuProfiler::instance_.Enabled();
}

extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
  return CpuProfiler::instance_.Start(fname, nullptr);
}

extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
    const char *fname, const ProfilerOptions *options) {
  return CpuProfiler::instance_.Start(fname, options);
}

extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
  CpuProfiler::instance_.Stop();
}

extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
    ProfilerState* state) {
  CpuProfiler::instance_.GetCurrentState(state);
}

extern "C" PERFTOOLS_DLL_DECL int ProfilerGetStackTrace(
    void** result, int max_depth, int skip_count, const void *uc) {
  return GetStackTraceWithContext(result, max_depth, skip_count, uc);
}

#else  // OS_CYGWIN

// ITIMER_PROF doesn't work under cygwin.  ITIMER_REAL is available, but doesn't
// work as well for profiling, and also interferes with alarm().  Because of
// these issues, unless a specific need is identified, profiler support is
// disabled under Cygwin.
extern "C" void ProfilerRegisterThread() { }
extern "C" void ProfilerFlush() { }
extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
extern "C" int ProfilerStart(const char* fname) { return 0; }
extern "C" int ProfilerStartWithOptions(const char *fname,
                                        const ProfilerOptions *options) {
  return 0;
}
extern "C" void ProfilerStop() { }
extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
  memset(state, 0, sizeof(*state));
}
extern "C" int ProfilerGetStackTrace(
    void** result, int max_depth, int skip_count, const void *uc) {
  return 0;
}

#endif  // OS_CYGWIN

// DEPRECATED routines
extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }
gperftools-gperftools-2.18/src/safe_strerror.cc000066400000000000000000000114761513545575200220150ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2023, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "safe_strerror.h"

#include 
#include 
#include 

namespace tcmalloc {

namespace {

const char* TryMapErrno(int errnum) {

#define C(v) if (errnum == v) return #v
#ifdef E2BIG
C(E2BIG);
#endif
#ifdef EACCES
C(EACCES);
#endif
#ifdef EADDRINUSE
C(EADDRINUSE);
#endif
#ifdef EADDRNOTAVAIL
C(EADDRNOTAVAIL);
#endif
#ifdef EAFNOSUPPORT
C(EAFNOSUPPORT);
#endif
#ifdef EAGAIN
C(EAGAIN);
#endif
#ifdef EALREADY
C(EALREADY);
#endif
#ifdef EBADF
C(EBADF);
#endif
#ifdef EBADMSG
C(EBADMSG);
#endif
#ifdef EBUSY
C(EBUSY);
#endif
#ifdef ECANCELED
C(ECANCELED);
#endif
#ifdef ECHILD
C(ECHILD);
#endif
#ifdef ECONNABORTED
C(ECONNABORTED);
#endif
#ifdef ECONNREFUSED
C(ECONNREFUSED);
#endif
#ifdef ECONNRESET
C(ECONNRESET);
#endif
#ifdef EDEADLK
C(EDEADLK);
#endif
#ifdef EDESTADDRREQ
C(EDESTADDRREQ);
#endif
#ifdef EDOM
C(EDOM);
#endif
#ifdef EDQUOT
C(EDQUOT);
#endif
#ifdef EEXIST
C(EEXIST);
#endif
#ifdef EFAULT
C(EFAULT);
#endif
#ifdef EFBIG
C(EFBIG);
#endif
#ifdef EHOSTUNREACH
C(EHOSTUNREACH);
#endif
#ifdef EIDRM
C(EIDRM);
#endif
#ifdef EILSEQ
C(EILSEQ);
#endif
#ifdef EINPROGRESS
C(EINPROGRESS);
#endif
#ifdef EINTR
C(EINTR);
#endif
#ifdef EINVAL
C(EINVAL);
#endif
#ifdef EIO
C(EIO);
#endif
#ifdef EISCONN
C(EISCONN);
#endif
#ifdef EISDIR
C(EISDIR);
#endif
#ifdef ELOOP
C(ELOOP);
#endif
#ifdef EMFILE
C(EMFILE);
#endif
#ifdef EMLINK
C(EMLINK);
#endif
#ifdef EMSGSIZE
C(EMSGSIZE);
#endif
#ifdef EMULTIHOP
C(EMULTIHOP);
#endif
#ifdef ENAMETOOLONG
C(ENAMETOOLONG);
#endif
#ifdef ENETDOWN
C(ENETDOWN);
#endif
#ifdef ENETRESET
C(ENETRESET);
#endif
#ifdef ENETUNREACH
C(ENETUNREACH);
#endif
#ifdef ENFILE
C(ENFILE);
#endif
#ifdef ENOBUFS
C(ENOBUFS);
#endif
#ifdef ENODATA
C(ENODATA);
#endif
#ifdef ENODEV
C(ENODEV);
#endif
#ifdef ENOENT
C(ENOENT);
#endif
#ifdef ENOEXEC
C(ENOEXEC);
#endif
#ifdef ENOLCK
C(ENOLCK);
#endif
#ifdef ENOLINK
C(ENOLINK);
#endif
#ifdef ENOMEM
C(ENOMEM);
#endif
#ifdef ENOMSG
C(ENOMSG);
#endif
#ifdef ENOPROTOOPT
C(ENOPROTOOPT);
#endif
#ifdef ENOSPC
C(ENOSPC);
#endif
#ifdef ENOSR
C(ENOSR);
#endif
#ifdef ENOSTR
C(ENOSTR);
#endif
#ifdef ENOSYS
C(ENOSYS);
#endif
#ifdef ENOTCONN
C(ENOTCONN);
#endif
#ifdef ENOTDIR
C(ENOTDIR);
#endif
#ifdef ENOTEMPTY
C(ENOTEMPTY);
#endif
#ifdef ENOTRECOVERABLE
C(ENOTRECOVERABLE);
#endif
#ifdef ENOTSOCK
C(ENOTSOCK);
#endif
#ifdef ENOTSUP
C(ENOTSUP);
#endif
#ifdef ENOTTY
C(ENOTTY);
#endif
#ifdef ENXIO
C(ENXIO);
#endif
#ifdef EOPNOTSUPP
C(EOPNOTSUPP);
#endif
#ifdef EOVERFLOW
C(EOVERFLOW);
#endif
#ifdef EOWNERDEAD
C(EOWNERDEAD);
#endif
#ifdef EPERM
C(EPERM);
#endif
#ifdef EPIPE
C(EPIPE);
#endif
#ifdef EPROTO
C(EPROTO);
#endif
#ifdef EPROTONOSUPPORT
C(EPROTONOSUPPORT);
#endif
#ifdef EPROTOTYPE
C(EPROTOTYPE);
#endif
#ifdef ERANGE
C(ERANGE);
#endif
#ifdef EROFS
C(EROFS);
#endif
#ifdef ESPIPE
C(ESPIPE);
#endif
#ifdef ESRCH
C(ESRCH);
#endif
#ifdef ESTALE
C(ESTALE);
#endif
#ifdef ETIME
C(ETIME);
#endif
#ifdef ETIMEDOUT
C(ETIMEDOUT);
#endif
#ifdef ETXTBSY
C(ETXTBSY);
#endif
#ifdef EWOULDBLOCK
C(EWOULDBLOCK);
#endif
#ifdef EXDEV
C(EXDEV);
#endif
#undef C

  return nullptr;
}

}  // namespace

SafeStrError::SafeStrError(int errnum) {
  result_ = TryMapErrno(errnum);
  if (result_ == nullptr) {
    snprintf(buf_, sizeof(buf_), "errno %d", errnum);
    result_ = buf_;
  }
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/safe_strerror.h000066400000000000000000000043641513545575200216550ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2023, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef SAFE_STRERROR_H
#define SAFE_STRERROR_H
#include "config.h"

#include "base/basictypes.h"

namespace tcmalloc {

// SafeStrError works pretty much like strerror, but it bypasses all
// the locale stuff (which will malloc occasionally). It simply
// returns errno constant name (like "ENOMEM"), or if errno is not
// recognized it will return "errno " string (kept in internal
// buf_ buffer).
class SafeStrError {
public:
  explicit ATTRIBUTE_VISIBILITY_HIDDEN SafeStrError(int errnum);
  const char* c_str() { return result_; }
private:
  const char* result_;
  char buf_[32];
};

}  // namespace tcmalloc


#endif  // SAFE_STRERROR_H
gperftools-gperftools-2.18/src/sampler.cc000066400000000000000000000122061513545575200205700ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// All Rights Reserved.
//
// Author: Daniel Ford

#include "sampler.h"

#include   // For min()
#include 

#include "base/commandlineflags.h"
#include "base/spinlock.h"
#include "base/sysinfo.h"

// The approximate gap in bytes between sampling actions.  See Init
// below for how it is initialized from TCMALLOC_SAMPLE_PARAMETER
// environment variable.
//
// I.e., we take one sample approximately once every
// tcmalloc_sample_parameter bytes of allocation
// i.e. about once every 512KB if value is 1<<19.
DEFINE_int64(tcmalloc_sample_parameter, 0, "");

namespace tcmalloc {

int Sampler::GetSamplePeriod() {
  return FLAGS_tcmalloc_sample_parameter;
}

// Run this before using your sampler
void Sampler::Init(uint64_t seed) {
  DCHECK_NE(seed, 0);

  // Initialize PRNG
  rnd_ = seed;
  // Step it forward 20 times for good measure
  for (int i = 0; i < 20; i++) {
    rnd_ = NextRandom(rnd_);
  }

#ifndef NO_TCMALLOC_SAMPLES
  static TrivialOnce setup_parameter;
  setup_parameter.RunOnce([] () {
    const char* val = GetenvBeforeMain("TCMALLOC_SAMPLE_PARAMETER");
    FLAGS_tcmalloc_sample_parameter = tcmalloc::commandlineflags::StringToLongLong(val, 0);
  });
#endif

  // Initialize counter
  bytes_until_sample_ = PickNextSamplingPoint();
}

static constexpr auto kMaxSSize = (static_cast(static_cast(static_cast(-1)) >> 1));

// Generates a geometric variable with the specified mean (512K by default).
// This is done by generating a random number between 0 and 1 and applying
// the inverse cumulative distribution function for an exponential.
// Specifically: Let m be the inverse of the sample period, then
// the probability distribution function is m*exp(-mx) so the CDF is
// p = 1 - exp(-mx), so
// q = 1 - p = exp(-mx)
// log_e(q) = -mx
// -log_e(q)/m = x
// log_2(q) * (-log_e(2) * 1/m) = x
// In the code, q is actually in the range 1 to 2**26, hence the -26 below
ssize_t Sampler::PickNextSamplingPoint() {
  if (FLAGS_tcmalloc_sample_parameter <= 0) {
    // In this case, we don't want to sample ever, and the larger a
    // value we put here, the longer until we hit the slow path
    // again. However, we have to support the flag changing at
    // runtime, so pick something reasonably large (to keep overhead
    // low) but small enough that we'll eventually start to sample
    // again.
    return 16 << 20;
  }

  rnd_ = NextRandom(rnd_);
  // Take the top 26 bits as the random number
  // (This plus the 1<<58 sampling bound give a max possible step of
  // 5194297183973780480 bytes.)
  const uint64_t prng_mod_power = 48;  // Number of bits in prng
  // The uint32_t cast is to prevent a (hard-to-reproduce) NAN
  // under piii debug for some binaries.
  double q = static_cast(rnd_ >> (prng_mod_power - 26)) + 1.0;
  // Put the computed p-value through the CDF of a geometric.
  double interval =
      (log2(q) - 26) * (-log(2.0) * FLAGS_tcmalloc_sample_parameter);

  // Very large values of interval overflow ssize_t. If we happen to
  // hit such improbable condition, we simply cheat and clamp interval
  // to largest supported value.
  return static_cast(
    std::min(interval, static_cast(kMaxSSize)));
}

bool Sampler::RecordAllocationSlow(size_t k) {
  if (!initialized_) {
    initialized_ = true;
    Init(reinterpret_cast(this));
    if (static_cast(bytes_until_sample_) >= k) {
      bytes_until_sample_ -= k;
      return true;
    }
  }
  bytes_until_sample_ = PickNextSamplingPoint();
  return FLAGS_tcmalloc_sample_parameter <= 0;
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/sampler.h000066400000000000000000000215771513545575200204450ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// All Rights Reserved.
//
// Author: Daniel Ford

#ifndef TCMALLOC_SAMPLER_H_
#define TCMALLOC_SAMPLER_H_

#include "config.h"
#include                      // for size_t
#include                      // for uint64_t, uint32_t, int32_t
#include                      // for memcpy

#include "base/basictypes.h"  // ssize_t
#include "base/logging.h"

namespace tcmalloc {

//-------------------------------------------------------------------
// Sampler to decide when to create a sample trace for an allocation
// Not thread safe: Each thread should have it's own sampler object.
// Caller must use external synchronization if used
// from multiple threads.
//
// With 512K average sample step (the default):
//  the probability of sampling a 4K allocation is about 0.00778
//  the probability of sampling a 1MB allocation is about 0.865
//  the probability of sampling a 1GB allocation is about 1.00000
// In general, the probablity of sampling is an allocation of size X
// given a flag value of Y (default 1M) is:
//  1 - e^(-X/Y)
//
// With 128K average sample step:
//  the probability of sampling a 1MB allocation is about 0.99966
//  the probability of sampling a 1GB allocation is about 1.0
//  (about 1 - 2**(-26))
// With 1M average sample step:
//  the probability of sampling a 4K allocation is about 0.00390
//  the probability of sampling a 1MB allocation is about 0.632
//  the probability of sampling a 1GB allocation is about 1.0
//
// The sampler works by representing memory as a long stream from
// which allocations are taken. Some of the bytes in this stream are
// marked and if an allocation includes a marked byte then it is
// sampled. Bytes are marked according to a Poisson point process
// with each byte being marked independently with probability
// p = 1/tcmalloc_sample_parameter.  This makes the probability
// of sampling an allocation of X bytes equal to the CDF of
// a geometric with mean tcmalloc_sample_parameter. (ie. the
// probability that at least one byte in the range is marked). This
// is accurately given by the CDF of the corresponding exponential
// distribution : 1 - e^(-X/tcmalloc_sample_parameter_)
// Independence of the byte marking ensures independence of
// the sampling of each allocation.
//
// This scheme is implemented by noting that, starting from any
// fixed place, the number of bytes until the next marked byte
// is geometrically distributed. This number is recorded as
// bytes_until_sample_.  Every allocation subtracts from this
// number until it is less than 0. When this happens the current
// allocation is sampled.
//
// When an allocation occurs, bytes_until_sample_ is reset to
// a new independtly sampled geometric number of bytes. The
// memoryless property of the point process means that this may
// be taken as the number of bytes after the end of the current
// allocation until the next marked byte. This ensures that
// very large allocations which would intersect many marked bytes
// only result in a single call to PickNextSamplingPoint.
//-------------------------------------------------------------------

class SamplerTest;

class Sampler {
 public:
  constexpr Sampler() {}

  // Initialize this sampler.
  void Init(uint64_t seed);

  // Record allocation of "k" bytes.  Return true if no further work
  // is need, and false if allocation needed to be sampled.
  bool RecordAllocation(size_t k);

  // Same as above (but faster), except:
  // a) REQUIRES(k < std::numeric_limits::max())
  // b) if this returns false, you must call RecordAllocation
  //    to confirm if sampling truly needed.
  //
  // The point of this function is to only deal with common case of no
  // sampling and let caller (which is in malloc fast-path) to
  // "escalate" to fuller and slower logic only if necessary.
  bool TryRecordAllocationFast(size_t k);

  // Generate a geometric with mean 512K (or FLAG_tcmalloc_sample_parameter)
  ssize_t PickNextSamplingPoint();

  // Returns the current sample period
  static int GetSamplePeriod();

  // The following are public for the purposes of testing
  static uint64_t NextRandom(uint64_t rnd_);  // Returns the next prng value

  // Bytes until we sample next.
  //
  // More specifically when bytes_until_sample_ is X, we can allocate
  // X bytes without triggering sampling; on the (X+1)th allocated
  // byte, the containing allocation will be sampled.
  //
  // Always non-negative with only very brief exceptions (see
  // TryRecordAllocationFast, so casting to size_t is ok.
 private:
  friend class SamplerTest;
  bool RecordAllocationSlow(size_t k);

  ssize_t bytes_until_sample_{};
  uint64_t rnd_{};  // Cheap random number generator
  bool initialized_{};
};

inline bool Sampler::RecordAllocation(size_t k) {
  // Note that we have to deal with arbitrarily large values of k
  // here. Thus we're upcasting bytes_until_sample_ to unsigned rather
  // than the other way around. And this is why this code cannot be
  // merged with DecrementFast code below.
  if (static_cast(bytes_until_sample_) < k) {
    bool result = RecordAllocationSlow(k);
    return result;
  } else {
    bytes_until_sample_ -= k;
    return true;
  }
}

inline bool Sampler::TryRecordAllocationFast(size_t k) {
  // For efficiency reason, we're testing bytes_until_sample_ after
  // decrementing it by k. This allows compiler to do sub , 
  // followed by conditional jump on sign. But it is correct only if k
  // is actually smaller than largest ssize_t value. Otherwise
  // converting k to signed value overflows.
  //
  // It would be great for generated code to be sub , 
  // followed by conditional jump on 'carry', which would work for
  // arbitrary values of k, but there seem to be no way to express
  // that in C++.
  //
  // Our API contract explicitly states that only small values of k
  // are permitted. And thus it makes sense to assert on that.
  DCHECK_GE(static_cast(k), 0);

  bytes_until_sample_ -= static_cast(k);
  if (PREDICT_FALSE(bytes_until_sample_ < 0)) {
    // Note, we undo sampling counter update, since we're not actually
    // handling slow path in the "needs sampling" case (calling
    // RecordAllocationSlow to reset counter). And we do that in order
    // to avoid non-tail calls in malloc fast-path. See also comments
    // on declaration inside Sampler class.
    //
    // volatile is used here to improve compiler's choice of
    // instuctions. We know that this path is very rare and that there
    // is no need to keep previous value of bytes_until_sample_ in
    // register. This helps compiler generate slightly more efficient
    // sub ,  instruction for subtraction above.
    volatile ssize_t *ptr =
        const_cast(&bytes_until_sample_);
    *ptr += k;
    return false;
  }
  return true;
}

// Inline functions which are public for testing purposes

// Returns the next prng value.
// pRNG is: aX+b mod c with a = 0x5DEECE66D, b =  0xB, c = 1<<48
// This is the lrand64 generator.
inline uint64_t Sampler::NextRandom(uint64_t rnd) {
  const uint64_t prng_mult = 0x5DEECE66DULL;
  const uint64_t prng_add = 0xB;
  const uint64_t prng_mod_power = 48;
  const uint64_t prng_mod_mask =
      ~((~static_cast(0)) << prng_mod_power);
  return (prng_mult * rnd + prng_add) & prng_mod_mask;
}

}  // namespace tcmalloc

#endif  // TCMALLOC_SAMPLER_H_
gperftools-gperftools-2.18/src/span.cc000066400000000000000000000052551513545575200200740ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#include 
#include "span.h"

#include "internal_logging.h"  // for ASSERT
#include "page_heap_allocator.h"  // for PageHeapAllocator
#include "static_vars.h"       // for Static

namespace tcmalloc {

Span* NewSpan(PageID p, Length len) {
  Span* result = new (Static::span_allocator()->New()) Span;

  result->start = p;
  result->length = len;
  return result;
}

void DeleteSpan(Span* span) {
  Static::span_allocator()->Delete(span);
}

void DLL_Init(Span* list) {
  list->next = list;
  list->prev = list;
}

void DLL_Remove(Span* span) {
  span->prev->next = span->next;
  span->next->prev = span->prev;
  span->prev = nullptr;
  span->next = nullptr;
}

int DLL_Length(const Span* list) {
  int result = 0;
  for (Span* s = list->next; s != list; s = s->next) {
    result++;
  }
  return result;
}

void DLL_Prepend(Span* list, Span* span) {
  ASSERT(span->next == nullptr);
  ASSERT(span->prev == nullptr);
  span->next = list->next;
  span->prev = list;
  list->next->prev = span;
  list->next = span;
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/span.h000066400000000000000000000133511513545575200177320ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 
//
// A Span is a contiguous run of pages.

#ifndef TCMALLOC_SPAN_H_
#define TCMALLOC_SPAN_H_

#include 

#include 

#include "common.h"
#include "page_heap_allocator.h"

namespace tcmalloc {

struct Span;

// Store a pointer to a span along with a cached copy of its length.
// These are used as set elements to improve the performance of
// comparisons during tree traversal: the lengths are inline with the
// tree nodes and thus avoid expensive cache misses to dereference
// the actual Span objects in most cases.
struct SpanPtrWithLength {
  explicit SpanPtrWithLength(Span* s);

  Span* span;
  Length length;
};
// Comparator for best-fit search, with address order as a tie-breaker.
struct SpanBestFitLess {
  bool operator()(SpanPtrWithLength a, SpanPtrWithLength b) const;
};

using SpanSet = std::set>;
using SpanSetIter = SpanSet::iterator;

// Information kept for a span (a contiguous run of pages).
struct Span {
  PageID        start;          // Starting page number
  Length        length;         // Number of pages in span
  Span*         next;           // Used when in link list
  Span*         prev;           // Used when in link list
  union {
    void* objects;              // Linked list of free objects

    // Span may contain iterator pointing back at SpanSet entry of
    // this span into set of large spans. It is used to quickly delete
    // spans from those sets. span_iter_space is space for such
    // iterator which lifetime is controlled explicitly.
    alignas(SpanSetIter) char span_iter_space[sizeof(SpanSetIter)];
  };
  unsigned int  refcount : 16;  // Number of non-free objects
  unsigned int  sizeclass : 8;  // Size-class for small objects (or 0)
  unsigned int  location : 2;   // Is the span on a freelist, and if so, which?
  unsigned int  sample : 1;     // Sampled object?
  bool          has_span_iter : 1; // Iff span_iter_space has valid
                                   // iterator. Only for debug builds.

  constexpr Span()
    : start{}, length{}, next{}, prev{}, objects{}, refcount{}, sizeclass{}, location{}, sample{}, has_span_iter{} {}

  // Sets iterator stored in span_iter_space.
  // Requires has_span_iter == 0.
  void SetSpanSetIterator(const SpanSetIter& iter);
  // Copies out and destroys iterator stored in span_iter_space.
  SpanSetIter ExtractSpanSetIterator();

  // What freelist the span is on: IN_USE if on none, or normal or returned
  enum { IN_USE, ON_NORMAL_FREELIST, ON_RETURNED_FREELIST };
};

inline SpanPtrWithLength::SpanPtrWithLength(Span* s)
    : span(s),
      length(s->length) {
}

inline bool SpanBestFitLess::operator()(SpanPtrWithLength a, SpanPtrWithLength b) const {
  if (a.length < b.length)
    return true;
  if (a.length > b.length)
    return false;
  return a.span->start < b.span->start;
}

inline void Span::SetSpanSetIterator(const SpanSetIter& iter) {
  ASSERT(!has_span_iter);
  has_span_iter = 1;

  new (span_iter_space) SpanSetIter(iter);
}

inline SpanSetIter Span::ExtractSpanSetIterator() {
  ASSERT(has_span_iter);
  has_span_iter = 0;

  SpanSetIter* this_iter =
    reinterpret_cast(span_iter_space);
  SpanSetIter retval = *this_iter;
  this_iter->~SpanSetIter();
  return retval;
}

// Allocator/deallocator for spans
Span* NewSpan(PageID p, Length len);
void DeleteSpan(Span* span);

// -------------------------------------------------------------------------
// Doubly linked list of spans.
// -------------------------------------------------------------------------

// Initialize *list to an empty list.
void DLL_Init(Span* list);

// Remove 'span' from the linked list in which it resides, updating
// the pointers of adjacent Spans and setting span's next and prev to
// nullptr.
void DLL_Remove(Span* span);

// Return true iff "list" is empty.
inline bool DLL_IsEmpty(const Span* list) {
  return list->next == list;
}

// Add span to the front of list.
void DLL_Prepend(Span* list, Span* span);

// Return the length of the linked list. O(n)
int DLL_Length(const Span* list);

}  // namespace tcmalloc

#endif  // TCMALLOC_SPAN_H_
gperftools-gperftools-2.18/src/stack_trace_table.cc000066400000000000000000000101071513545575200225550ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Andrew Fikes

#include "config.h"

#include "stack_trace_table.h"

#include "base/spinlock.h"              // for SpinLockHolder
#include "common.h"            // for StackTrace
#include "internal_logging.h"  // for ASSERT, Log
#include "page_heap_allocator.h"  // for PageHeapAllocator
#include "static_vars.h"       // for Static

namespace tcmalloc {

std::unique_ptr ProduceStackTracesDump(const StackTrace* (*next_fn)(const void** current_head),
                                                const void* head) {
  int depth_total = 0;
  int bucket_total = 0;
  for (const void* entry = head; entry != nullptr;) {
    const StackTrace* trace = next_fn(&entry);
    depth_total += trace->depth;
    bucket_total++;
  }

  int out_len = bucket_total * 3 + depth_total + 1;
  std::unique_ptr out{new void*[out_len]};

  int idx = 0;
  for (const void* entry = head; entry != nullptr;) {
    const StackTrace* trace = next_fn(&entry);
    out[idx++] = reinterpret_cast(uintptr_t{1});   // count
    out[idx++] = reinterpret_cast(trace->size);  // cumulative size
    out[idx++] = reinterpret_cast(trace->depth);
    for (int d = 0; d < trace->depth; ++d) {
      out[idx++] = trace->stack[d];
    }
  }
  out[idx++] = nullptr;
  ASSERT(idx == out_len);

  return out;
}

// In order to avoid dependencies we're only unit-testing function
// above. Stuff below pulls too much and isn't worth own unit-test
// (already covered by sampling_test).
#ifndef STACK_TRACE_TABLE_IS_TESTED

void StackTraceTable::AddTrace(const StackTrace& t) {
  if (error_) {
    return;
  }

  Entry* entry = allocator_.allocate(1);
  if (entry == nullptr) {
    Log(kLog, __FILE__, __LINE__,
        "tcmalloc: could not allocate bucket", sizeof(*entry));
    error_ = true;
  } else {
    entry->trace = t;
    entry->next = head_;
    head_ = entry;
  }
}

void** StackTraceTable::ReadStackTracesAndClear() {
  std::unique_ptr out = ProduceStackTracesDump(
    +[] (const void** current_head) -> const StackTrace* {
      const Entry* head = static_cast(*current_head);
      *current_head = head->next;
      return &head->trace;
    }, head_);

  // Clear state
  error_ = false;

  SpinLockHolder h(Static::pageheap_lock());
  Entry* entry = head_;
  while (entry != nullptr) {
    Entry* next = entry->next;
    allocator_.deallocate(entry, 1);
    entry = next;
  }
  head_ = nullptr;

  return out.release();
}

#endif // STACK_TRACE_TABLE_IS_TESTED

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/stack_trace_table.h000066400000000000000000000061051513545575200224220ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Andrew Fikes
//
// Utility class for coalescing sampled stack traces.  Not thread-safe.

#ifndef TCMALLOC_STACK_TRACE_TABLE_H_
#define TCMALLOC_STACK_TRACE_TABLE_H_
#include "config.h"

#include                      // for uintptr_t

#include 

#include "common.h"
#include "internal_logging.h"
#include "page_heap_allocator.h"

namespace tcmalloc {

// Given snapshot of StackTrace list, new[] list of machine words and
// fill that with profile. See
// MallocExtension::GetStackTraces. next_fn and head are
// representation of generalized iterator over that list. See uses to
// learn how it works.
std::unique_ptr ProduceStackTracesDump(const StackTrace* (*next_fn)(const void** updatable_head),
                                                const void* head);

class StackTraceTable {
 public:
  // REQUIRES: L < pageheap_lock
  StackTraceTable() = default;
  ~StackTraceTable() {
    ASSERT(head_ == nullptr);
  }

  // Adds stack trace "t" to table.
  //
  // REQUIRES: L >= pageheap_lock
  void AddTrace(const StackTrace& t);

  // Returns stack traces formatted per MallocExtension guidelines.
  // May return nullptr on error.  Clears state before returning.
  //
  // REQUIRES: L < pageheap_lock
  void** ReadStackTracesAndClear();

 private:
  struct Entry {
    Entry* next;
    StackTrace trace;
  };

  bool error_{};
  Entry* head_{};
  STLPageHeapAllocator allocator_;
};

}  // namespace tcmalloc

#endif  // TCMALLOC_STACK_TRACE_TABLE_H_
gperftools-gperftools-2.18/src/stacktrace.cc000066400000000000000000000355711513545575200212630ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// Copyright (c) 2023, gperftools Contributors.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Original Author: Sanjay Ghemawat.
//
// Most recent significant rework and extensions: Aliaksei
// Kandratsenka (all bugs are mine).
//
// Produce stack trace.
//
// There few different ways we can try to get the stack trace:
//
// 1) Our hand-coded stack-unwinder.  This depends on a certain stack
//    layout, which is used by various ABIs. It uses the frame
//    pointer to do its work.
//
// 2) The libunwind library. It also doesn't call malloc (in most
//    configurations). Note, there are at least 3 libunwind
//    implementations currently available. "Original" libunwind,
//    llvm's and Android's. Only original library has been tested so
//    far.
//
// 3) The "libgcc" unwinder -- also the one used by the c++ exception
//    code. It uses _Unwind_Backtrace facility of modern ABIs. Some
//    implementations occasionally call into malloc (which we're able
//    to handle). Some implementations also use some internal locks,
//    so it is not entirely compatible with backtracing from signal
//    handlers.
//
// 4) backtrace() unwinder (available in glibc and execinfo on some
//    BSDs). It is typically, but not always implemented on top of
//    "libgcc" unwinder. So we have it. We use this one on OSX.
//
// 5) On windows we use RtlCaptureStackBackTrace.
//
// Note: if you add a new implementation here, make sure it works
// correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that.

#include 
#include  // for getenv
#include  // for strcmp
#include  // for fprintf
#include "gperftools/stacktrace.h"
#include "base/commandlineflags.h"
#include "base/googleinit.h"
#include "getenv_safe.h"


// we're using plain struct and not class to avoid any possible issues
// during initialization. Struct of pointers is easy to init at
// link-time.
struct GetStackImplementation {
  int (*GetStackFramesPtr)(void** result, int* sizes, int max_depth,
                           int skip_count);

  int (*GetStackFramesWithContextPtr)(void** result, int* sizes, int max_depth,
                                      int skip_count, const void *uc);

  int (*GetStackTracePtr)(void** result, int max_depth,
                          int skip_count);

  int (*GetStackTraceWithContextPtr)(void** result, int max_depth,
                                  int skip_count, const void *uc);

  const char *name;
};

#if HAVE_DECL_BACKTRACE
#define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h"
#define GST_SUFFIX generic
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_generic
#endif

#ifdef HAVE_UNWIND_BACKTRACE
#define STACKTRACE_INL_HEADER "stacktrace_libgcc-inl.h"
#define GST_SUFFIX libgcc
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_libgcc
#endif

// libunwind uses __thread so we check for both libunwind.h and
// __thread support
#if defined(USE_LIBUNWIND)
#define STACKTRACE_INL_HEADER "stacktrace_libunwind-inl.h"
#define GST_SUFFIX libunwind
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_libunwind
#endif // USE_LIBUNWIND

#if !defined(_WIN32) && defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__riscv) || defined(__arm__))
// NOTE: legacy 32-bit arm works fine with recent clangs, but is broken in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92172
#define STACKTRACE_INL_HEADER "stacktrace_generic_fp-inl.h"
#define GST_SUFFIX generic_fp
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_generic_fp

#undef TCMALLOC_UNSAFE_GENERIC_FP_STACKTRACE
#define TCMALLOC_UNSAFE_GENERIC_FP_STACKTRACE 1

#define STACKTRACE_INL_HEADER "stacktrace_generic_fp-inl.h"
#define GST_SUFFIX generic_fp_unsafe
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_generic_fp_unsafe
#endif

#if !defined(TCMALLOC_DISABLE_PPC_FRAME_POINTER_BACKTRACER)
#if defined(__ppc__) || defined(__PPC__)
#if defined(__linux__)
#define STACKTRACE_INL_HEADER "stacktrace_powerpc-linux-inl.h"
#else
#define STACKTRACE_INL_HEADER "stacktrace_powerpc-darwin-inl.h"
#endif
#define GST_SUFFIX ppc
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_ppc
#endif
#endif  // !TCMALLOC_DISABLE_PPC_FRAME_POINTER_BACKTRACER

#if defined(__arm__)
#define STACKTRACE_INL_HEADER "stacktrace_arm-inl.h"
#define GST_SUFFIX arm
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_arm
#endif

#ifdef TCMALLOC_ENABLE_INSTRUMENT_STACKTRACE
#define STACKTRACE_INL_HEADER "stacktrace_instrument-inl.h"
#define GST_SUFFIX instrument
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_instrument
#endif

// The Windows case -- probably cygwin and mingw will use one of the
// x86-includes above, but if not, we can fall back to windows intrinsics.
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__)
#define STACKTRACE_INL_HEADER "stacktrace_win32-inl.h"
#define GST_SUFFIX win32
#include "stacktrace_impl_setup-inl.h"
#undef GST_SUFFIX
#undef STACKTRACE_INL_HEADER
#define HAVE_GST_win32
#endif

#if __cplusplus >= 202302L
# ifndef HAS_SOME_STACKTRACE_IMPL
#  warning "Warning: no stacktrace capturing implementation for your OS"
# endif
#endif

#if (__x86_64__ || __i386__) && FORCED_FRAME_POINTERS
// x86-es (even i386 this days) default to no frame pointers. But
// historically we defaulted to frame pointer unwinder whenever
// --enable-frame-pointers is given. So we keep this behavior.
#define PREFER_FP_UNWINDER 1
#elif TCMALLOC_DONT_PREFER_LIBUNWIND && !defined(PREFER_LIBGCC_UNWINDER)
#define PREFER_FP_UNWINDER 1
#elif defined(__QNXNTO__) && !defined(PREFER_LIBGCC_UNWINDER)
#define PREFER_FP_UNWINDER 1
#else
#define PREFER_FP_UNWINDER 0
#endif

#if defined(PREFER_LIBGCC_UNWINDER) && !defined(HAVE_GST_libgcc)
#error user asked for libgcc unwinder to be default but it is not available
#endif

static int null_GetStackFrames(void** result, int* sizes, int max_depth,
                               int skip_count) {
  return 0;
}

static int null_GetStackFramesWithContext(void** result, int* sizes, int max_depth,
                                          int skip_count, const void *uc) {
  return 0;
}

static int null_GetStackTrace(void** result, int max_depth,
                              int skip_count) {
  return 0;
}

static int null_GetStackTraceWithContext(void** result, int max_depth,
                                         int skip_count, const void *uc) {
  return 0;
}

static GetStackImplementation impl__null = {
  null_GetStackFrames,
  null_GetStackFramesWithContext,
  null_GetStackTrace,
  null_GetStackTraceWithContext,
  "null"
};

static GetStackImplementation *all_impls[] = {
#ifdef HAVE_GST_instrument
  &impl__instrument,
#endif
#ifdef HAVE_GST_win32
  &impl__win32,
#endif
#ifdef HAVE_GST_ppc
  &impl__ppc,
#endif
#if defined(HAVE_GST_generic_fp) && PREFER_FP_UNWINDER
  &impl__generic_fp,
  &impl__generic_fp_unsafe,
#endif
#if defined(HAVE_GST_libgcc) && defined(PREFER_LIBGCC_UNWINDER)
  &impl__libgcc,
#endif
#ifdef HAVE_GST_libunwind
  &impl__libunwind,
#endif
#if defined(HAVE_GST_libgcc) && !defined(PREFER_LIBGCC_UNWINDER)
  &impl__libgcc,
#endif
#ifdef HAVE_GST_generic
  &impl__generic,
#endif
#if defined(HAVE_GST_generic_fp) && !PREFER_FP_UNWINDER
  &impl__generic_fp,
  &impl__generic_fp_unsafe,
#endif
#ifdef HAVE_GST_arm
  &impl__arm,
#endif
  &impl__null
};

static bool get_stack_impl_inited;
static GetStackImplementation *get_stack_impl;

#if 0
// This is for the benefit of code analysis tools that may have
// trouble with the computed #include above.
# include "stacktrace_libunwind-inl.h"
# include "stacktrace_generic-inl.h"
# include "stacktrace_generic_fp-inl.h"
# include "stacktrace_powerpc-linux-inl.h"
# include "stacktrace_win32-inl.h"
# include "stacktrace_arm-inl.h"
# include "stacktrace_instrument-inl.h"
#endif

static void init_default_stack_impl_inner(void);

namespace {

struct CaptureScope {
  void** const result;

  CaptureScope(void** result) : result(result) {
    init_default_stack_impl_inner();
  }

  ~CaptureScope() {
    // This "work" that we're doing ensures we're not tail-calling
    // stacktrace capturing implementation.
    (void)*(const_cast(result));
  }
};

}  // namespace

ATTRIBUTE_NOINLINE
PERFTOOLS_DLL_DECL int GetStackFrames(void** result, int* sizes, int max_depth,
                                      int skip_count) {
  CaptureScope scope(result);;

  return get_stack_impl->GetStackFramesPtr(result, sizes,
                                           max_depth, skip_count);
}

ATTRIBUTE_NOINLINE
PERFTOOLS_DLL_DECL int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
                                                 int skip_count, const void *uc) {
  CaptureScope scope(result);

  return get_stack_impl->GetStackFramesWithContextPtr(result, sizes, max_depth,
                                                      skip_count, uc);
}

ATTRIBUTE_NOINLINE
PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth,
                                     int skip_count) {
  CaptureScope scope(result);

  return get_stack_impl->GetStackTracePtr(result, max_depth, skip_count);
}

ATTRIBUTE_NOINLINE
PERFTOOLS_DLL_DECL int GetStackTraceWithContext(void** result, int max_depth,
                                                int skip_count, const void *uc) {
  CaptureScope scope(result);

  return get_stack_impl->GetStackTraceWithContextPtr(result, max_depth,
                                                     skip_count, uc);
}

#if STACKTRACE_IS_TESTED
static void init_default_stack_impl_inner() {
}

extern "C" {
const char* TEST_bump_stacktrace_implementation(const char* suggestion) {
  static int selection;
  constexpr int n = sizeof(all_impls)/sizeof(all_impls[0]);

  if (!get_stack_impl_inited) {
    fprintf(stderr, "Supported stacktrace methods:\n");
    for (int i = 0; i < n; i++) {
      fprintf(stderr, "* %s\n", all_impls[i]->name);
    }
    fprintf(stderr, "\n\n");
    get_stack_impl_inited = true;
  }

  do {
    if (selection == n) {
      return nullptr;
    }
    get_stack_impl = all_impls[selection++];

    if (suggestion && strcmp(suggestion, get_stack_impl->name) != 0) {
      continue;
    }
    if (get_stack_impl == &impl__null) {
      // skip null implementation
      continue;
    }
#ifdef HAVE_GST_arm
    if (get_stack_impl == &impl__arm) {
      // "arm" backtracer is hopelessly broken. So don't test. We
      // still ship it, though, just in case.
      continue;
    }
#endif  // HAVE_GST_arm
#if defined(HAVE_GST_generic_fp) && (!__x86_64__ && !__i386__ && !__aarch64__ && !__riscv)
    // Those "major" architectures have functional frame pointer
    // backtracer and they're built with -fno-omit-frame-pointers
    // -mno-omit-leaf-frame-pointer. So we do expect those tests to
    // succeed. Everyone else (e.g. 32-bit legacy arm) is unlikely to
    // pass.
    if (get_stack_impl == &impl__generic_fp || get_stack_impl == &impl__generic_fp_unsafe) {
      continue;
    }
#endif  // generic_fp && !"good architecture"
    break;
  } while (true);

  return get_stack_impl->name;
}
}

#else  // !STACKTRACE_IS_TESTED

ATTRIBUTE_NOINLINE
static void maybe_convert_libunwind_to_generic_fp() {
#if defined(HAVE_GST_libunwind) && defined(HAVE_GST_generic_fp)
  if (get_stack_impl != &impl__libunwind) {
    return;
  }

  bool want_to_replace = false;

  // Sometime recently, aarch64 had completely borked libunwind, so
  // lets test this case and fall back to frame pointers (which is
  // nearly but not quite perfect). So lets check this case.
  void* stack[4];
  int rv = get_stack_impl->GetStackTracePtr(stack, 4, 0);
  want_to_replace = (rv <= 2);

  if (want_to_replace) {
    get_stack_impl = &impl__generic_fp;
  }
#endif  // have libunwind and generic_fp
}

static void init_default_stack_impl_inner(void) {
  if (get_stack_impl_inited) {
    return;
  }
  get_stack_impl = all_impls[0];
  get_stack_impl_inited = true;
  const char *val = TCMallocGetenvSafe("TCMALLOC_STACKTRACE_METHOD");
  if (!val || !*val) {
    // If no explicit implementation is requested, consider changing
    // libunwind->generic_fp in some cases.
    maybe_convert_libunwind_to_generic_fp();
    return;
  }
  for (int i = 0; i < sizeof(all_impls) / sizeof(all_impls[0]); i++) {
    GetStackImplementation *c = all_impls[i];
    if (strcmp(c->name, val) == 0) {
      get_stack_impl = c;
      return;
    }
  }
  fprintf(stderr, "Unknown or unsupported stacktrace method requested: %s. Ignoring it\n", val);
}

ATTRIBUTE_NOINLINE
static void init_default_stack_impl(void) {
  init_default_stack_impl_inner();
  if (EnvToBool("TCMALLOC_STACKTRACE_METHOD_VERBOSE", false)) {
    fprintf(stderr, "Chosen stacktrace method is %s\nSupported methods:\n", get_stack_impl->name);
    for (int i = 0; i < sizeof(all_impls) / sizeof(all_impls[0]); i++) {
      GetStackImplementation *c = all_impls[i];
      fprintf(stderr, "* %s\n", c->name);
    }
    fputs("\nUse TCMALLOC_STACKTRACE_METHOD environment variable to override\n", stderr);
  }
}

REGISTER_MODULE_INITIALIZER(stacktrace_init_default_stack_impl, init_default_stack_impl());

#endif  // !STACKTRACE_IS_TESTED
gperftools-gperftools-2.18/src/stacktrace_arm-inl.h000066400000000000000000000137621513545575200225420ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Doug Kwan
// This is inspired by Craig Silverstein's PowerPC stacktrace code.
//

#ifndef BASE_STACKTRACE_ARM_INL_H_
#define BASE_STACKTRACE_ARM_INL_H_
// Note: this file is included into stacktrace.cc more than once.
// Anything that should only be defined once should be here:

#include    // for uintptr_t

#include "base/basictypes.h"
#include 

// WARNING:
// This only works if all your code is in either ARM or THUMB mode.  With
// interworking, the frame pointer of the caller can either be in r11 (ARM
// mode) or r7 (THUMB mode).  A callee only saves the frame pointer of its
// mode in a fixed location on its stack frame.  If the caller is a different
// mode, there is no easy way to find the frame pointer.  It can either be
// still in the designated register or saved on stack along with other callee
// saved registers.

// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template
static void **NextStackFrame(void **old_sp) {
  void **new_sp = (void**) old_sp[-1];

  // Check that the transition from frame pointer old_sp to frame
  // pointer new_sp isn't clearly bogus
  if (STRICT_UNWINDING) {
    // With the stack growing downwards, older stack frame must be
    // at a greater address that the current one.
    if (new_sp <= old_sp) return nullptr;
    // Assume stack frames larger than 100,000 bytes are bogus.
    if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
  } else {
    // In the non-strict mode, allow discontiguous stack frames.
    // (alternate-signal-stacks for example).
    if (new_sp == old_sp) return nullptr;
    // And allow frames upto about 1MB.
    if ((new_sp > old_sp)
        && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr;
  }
  if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr;
  return new_sp;
}

// This ensures that GetStackTrace stes up the Link Register properly.
#ifdef __GNUC__
void StacktraceArmDummyFunction() __attribute__((noinline));
void StacktraceArmDummyFunction() { __asm__ volatile(""); }
#else
# error StacktraceArmDummyFunction() needs to be ported to this platform.
#endif
#endif  // BASE_STACKTRACE_ARM_INL_H_

// Note: this part of the file is included several times.
// Do not put globals below.

// The following 4 functions are generated from the code below:
//   GetStack{Trace,Frames}()
//   GetStack{Trace,Frames}WithContext()
//
// These functions take the following args:
//   void** result: the stack-trace, as an array
//   int* sizes: the size of each stack frame, as an array
//               (GetStackFrames* only)
//   int max_depth: the size of the result (and sizes) array(s)
//   int skip_count: how many stack pointers to skip before storing in result
//   void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)
static int GET_STACK_TRACE_OR_FRAMES {
#ifdef __GNUC__
  void **sp = reinterpret_cast(__builtin_frame_address(0));
#else
# error reading stack point not yet supported on this platform.
#endif

  // On ARM, the return address is stored in the link register (r14).
  // This is not saved on the stack frame of a leaf function.  To
  // simplify code that reads return addresses, we call a dummy
  // function so that the return address of this function is also
  // stored in the stack frame.  This works at least for gcc.
  StacktraceArmDummyFunction();

  skip_count++; // skip parent frame due to indirection in stacktrace.cc

  int n = 0;
  while (sp && n < max_depth) {
    // The GetStackFrames routine is called when we are in some
    // informational context (the failure signal handler for example).
    // Use the non-strict unwinding rules to produce a stack trace
    // that is as complete as possible (even if it contains a few bogus
    // entries in some rare cases).
    void **next_sp = NextStackFrame(sp);

    if (skip_count > 0) {
      skip_count--;
    } else {
      result[n] = *sp;

#if IS_STACK_FRAMES
      if (next_sp > sp) {
        sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
      } else {
        // A frame-size of 0 is used to indicate unknown frame size.
        sizes[n] = 0;
      }
#endif
      n++;
    }
    sp = next_sp;
  }
  return n;
}
gperftools-gperftools-2.18/src/stacktrace_generic-inl.h000066400000000000000000000065301513545575200233720ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// Portable implementation - just use glibc
//
// Note:  The glibc implementation may cause a call to malloc.
// This can cause a deadlock in HeapProfiler.

#ifndef BASE_STACKTRACE_GENERIC_INL_H_
#define BASE_STACKTRACE_GENERIC_INL_H_
// Note: this file is included into stacktrace.cc more than once.
// Anything that should only be defined once should be here:

#include 
#include 
#include "gperftools/stacktrace.h"
#endif  // BASE_STACKTRACE_GENERIC_INL_H_

// Note: this part of the file is included several times.
// Do not put globals below.

// The following 4 functions are generated from the code below:
//   GetStack{Trace,Frames}()
//   GetStack{Trace,Frames}WithContext()
//
// These functions take the following args:
//   void** result: the stack-trace, as an array
//   int* sizes: the size of each stack frame, as an array
//               (GetStackFrames* only)
//   int max_depth: the size of the result (and sizes) array(s)
//   int skip_count: how many stack pointers to skip before storing in result
//   void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)
static int GET_STACK_TRACE_OR_FRAMES {
  static const int kStackLength = 64;
  void * stack[kStackLength];
  int size;

  size = backtrace(stack, kStackLength);
  skip_count += 2;  // we want to skip the current and it's parent frame as well
  int result_count = size - skip_count;
  if (result_count < 0)
    result_count = 0;
  if (result_count > max_depth)
    result_count = max_depth;
  for (int i = 0; i < result_count; i++)
    result[i] = stack[i + skip_count];

#if IS_STACK_FRAMES
  // No implementation for finding out the stack frame sizes yet.
  memset(sizes, 0, sizeof(*sizes) * result_count);
#endif

  return result_count;
}
gperftools-gperftools-2.18/src/stacktrace_generic_fp-inl.h000066400000000000000000000302571513545575200240620ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2021, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// This file contains "generic" stack frame pointer backtracing
// code. Attempt is made to minimize amount of arch- or os-specific
// code and keep everything as generic as possible. Currently
// supported are x86-64, aarch64 and riscv.
#ifndef BASE_STACKTRACE_GENERIC_FP_INL_H_
#define BASE_STACKTRACE_GENERIC_FP_INL_H_

#if HAVE_SYS_UCONTEXT_H
#include 
#elif HAVE_UCONTEXT_H
#include 
#endif

// This is only used on OS-es with mmap support.
#include 

#if HAVE_SYS_UCONTEXT_H || HAVE_UCONTEXT_H

#define DEFINE_TRIVIAL_GET
#include "getpc.h"

#if !defined(HAVE_TRIVIAL_GET) && !defined(__NetBSD__)
#error sanity
#endif

#define HAVE_GETPC 1
#endif

#include 

#include "check_address-inl.h"

// our Autoconf setup enables -fno-omit-frame-pointer, but lets still
// ask for it just in case.
//
// Note: clang doesn't know about optimize attribute. But clang (and
// gcc too, apparently) automagically forces generation of frame
// pointer whenever __builtin_frame_address is used.
#if defined(__GNUC__) && defined(__has_attribute)
#if __has_attribute(optimize)
#define ENABLE_FP_ATTRIBUTE __attribute__((optimize("no-omit-frame-pointer")))
#endif
#endif

#ifndef ENABLE_FP_ATTRIBUTE
#define ENABLE_FP_ATTRIBUTE
#endif

namespace {
namespace stacktrace_generic_fp {

#if __x86_64__ && !_LP64
// x32 uses 64-bit stack entries but 32-bit addresses.
#define PAD_FRAME
#endif

#if __aarch64__
// Aarch64 has pointer authentication and uses the upper 16bit of a stack
// or return address to sign it. These bits needs to be strip in order for
// stacktraces to work.
void *strip_PAC(void* _ptr) {
  void *ret;
  asm volatile(
      "mov x30, %1\n\t"
      "hint #7\n\t"  // xpaclri, is NOP for < armv8.3-a
      "mov %0, x30\n\t"
      : "=r"(ret)
      : "r"(_ptr)
      : "x30");
  return ret;
}

#define STRIP_PAC(x) (strip_PAC((x)))
#else
#define STRIP_PAC(x) (x)
#endif

struct frame {
  uintptr_t parent;
#ifdef PAD_FRAME
  uintptr_t padding0;
#endif
  void* pc;
#ifdef PAD_FRAME
  uintptr_t padding1;
#endif
};

frame* adjust_fp(frame* f) {
#ifdef __riscv
  return f - 1;
#else
  return f;
#endif
}

bool CheckPageIsReadable(void* ptr, void* checked_ptr) {
  static uintptr_t pagesize;
  if (pagesize == 0) {
    pagesize = getpagesize();
  }

  uintptr_t addr = reinterpret_cast(ptr);
  uintptr_t parent_frame = reinterpret_cast(checked_ptr);

  parent_frame &= ~(pagesize - 1);
  addr &= ~(pagesize - 1);

  if (parent_frame != 0 && addr == parent_frame) {
    return true;
  }

  return CheckAddress(addr, pagesize);
}

template 
ATTRIBUTE_NOINLINE // forces architectures with link register to save it
ENABLE_FP_ATTRIBUTE
int capture(void **result, int max_depth, int skip_count,
            void* initial_frame, void* const * initial_pc,
            int *sizes) {
  int i = 0;

  if (initial_pc != nullptr) {
    // This is 'with ucontext' case. We take first pc from ucontext
    // and then skip_count is ignored as we assume that caller only
    // needed stack trace up to signal handler frame.
    skip_count = 0;
    if (max_depth == 0) {
      return 0;
    }
    result[0] = STRIP_PAC(*initial_pc);

    i++;
  }

  max_depth += skip_count;

  constexpr uintptr_t kTooSmallAddr = 16 << 10;
  constexpr uintptr_t kFrameSizeThreshold = 128 << 10;

#ifdef __arm__
  // note, (32-bit, legacy) arm support is not entirely functional
  // w.r.t. frame-pointer-based backtracing. Only recent clangs
  // generate "right" frame pointer setup and only with
  // --enable-frame-pointers. Current gcc-s are hopeless (somewhat
  // older gcc's (circa gcc 6 or so) did something that looks right,
  // but not recent ones).
  constexpr uintptr_t kAlignment = 4;
#elif defined(__aarch64__)
  // aarch64 ABI does not specify the frame pointer location, so we can only
  // know it's 8 byte aligned (as the register size)
  constexpr uintptr_t kAlignment = 8;
#else
  // This is simplistic yet. Here we're targeting x86 and
  // riscv. They all have 16 bytes stack alignment (even 32 bit
  // riscv). This can be made more elaborate as we consider more
  // architectures.
  constexpr uintptr_t kAlignment = 16;
#endif

  uintptr_t current_frame_addr = reinterpret_cast(__builtin_frame_address(0));
  uintptr_t initial_frame_addr = reinterpret_cast(initial_frame);
  if (((initial_frame_addr + sizeof(frame)) & (kAlignment - 1)) != 0) {
    return i;
  }
  if (initial_frame_addr < kTooSmallAddr) {
    return i;
  }
  if (initial_frame_addr - current_frame_addr > kFrameSizeThreshold) {
    return i;
  }

  // Note, we assume here that this functions frame pointer is not
  // bogus. Which is true if this code is built with
  // -fno-omit-frame-pointer.
  frame* prev_f = reinterpret_cast(current_frame_addr);
  frame *f = adjust_fp(reinterpret_cast(initial_frame));

  while (i < max_depth) {
    if (!UnsafeAccesses
        && !CheckPageIsReadable(&f->parent, prev_f)) {
      break;
    }

    void* pc = f->pc;
    if (pc == nullptr) {
      break;
    }

    if (i >= skip_count) {
      if (WithSizes) {
        sizes[i - skip_count] = reinterpret_cast(prev_f) - reinterpret_cast(f);
      }
      result[i - skip_count] = STRIP_PAC(pc);
    }

    i++;

    uintptr_t parent_frame_addr = f->parent;
    uintptr_t child_frame_addr = reinterpret_cast(f);

    if (parent_frame_addr < kTooSmallAddr) {
      break;
    }

    // stack grows towards smaller addresses, so if we didn't see
    // frame address increased (going from child to parent), it is bad
    // frame. We also test if frame is too big since that is another
    // sign of bad stack frame.
    if (parent_frame_addr - child_frame_addr > kFrameSizeThreshold) {
      break;
    }

    if (((parent_frame_addr + sizeof(frame)) & (kAlignment - 1)) != 0) {
      // not aligned, so we keep it safe and assume frame is bogus
      break;
    }

    prev_f = f;

    f = adjust_fp(reinterpret_cast(parent_frame_addr));
  }
  if (WithSizes && i > 0 && skip_count == 0) {
    sizes[0] = 0;
  }
  if (skip_count > i) {
    // Avoid returning negative depth.
    i = skip_count;
  }
  return i - skip_count;
}

}  // namespace stacktrace_generic_fp
}  // namespace

#endif  // BASE_STACKTRACE_GENERIC_FP_INL_H_

// Note: this part of the file is included several times.
// Do not put globals below.

// The following 4 functions are generated from the code below:
//   GetStack{Trace,Frames}()
//   GetStack{Trace,Frames}WithContext()
//
// These functions take the following args:
//   void** result: the stack-trace, as an array
//   int* sizes: the size of each stack frame, as an array
//               (GetStackFrames* only)
//   int max_depth: the size of the result (and sizes) array(s)
//   int skip_count: how many stack pointers to skip before storing in result
//   void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)

// Set this to true to disable "probing" of addresses that are read to
// make backtracing less-safe, but faster.
#ifndef TCMALLOC_UNSAFE_GENERIC_FP_STACKTRACE
#define TCMALLOC_UNSAFE_GENERIC_FP_STACKTRACE 0
#endif

ENABLE_FP_ATTRIBUTE
static int GET_STACK_TRACE_OR_FRAMES {
  if (max_depth == 0) {
    return 0;
  }

#if IS_STACK_FRAMES
  constexpr bool WithSizes = true;
  memset(sizes, 0, sizeof(*sizes) * max_depth);
#else
  constexpr bool WithSizes = false;
  int * const sizes = nullptr;
#endif

  // one for this function
  skip_count += 1;

  void* const * initial_pc = nullptr;
  void* initial_frame = __builtin_frame_address(0);
  int n;

#if IS_WITH_CONTEXT && (HAVE_SYS_UCONTEXT_H || HAVE_UCONTEXT_H)
  if (ucp) {
    auto uc = static_cast(ucp);

    // We have to resort to macro since different architectures have
    // different concrete types for those args.
#define SETUP_FRAME(pc_ptr, frame_addr)         \
    do { \
      initial_pc = reinterpret_cast(pc_ptr); \
      initial_frame = reinterpret_cast(frame_addr); \
    } while (false)

#if __linux__ && __riscv
    SETUP_FRAME(&uc->uc_mcontext.__gregs[REG_PC], uc->uc_mcontext.__gregs[REG_S0]);
#elif __linux__ && __aarch64__
    SETUP_FRAME(&uc->uc_mcontext.pc, uc->uc_mcontext.regs[29]);
#elif __linux__ && __arm__
    // Note: arm's frame pointer support is borked in recent GCC-s.
    SETUP_FRAME(&uc->uc_mcontext.arm_pc, uc->uc_mcontext.arm_fp);
#elif __linux__ && __i386__
    SETUP_FRAME(&uc->uc_mcontext.gregs[REG_EIP], uc->uc_mcontext.gregs[REG_EBP]);
#elif __linux__ && __x86_64__
    SETUP_FRAME(&uc->uc_mcontext.gregs[REG_RIP], uc->uc_mcontext.gregs[REG_RBP]);
#elif __FreeBSD__ && __x86_64__
    SETUP_FRAME(&uc->uc_mcontext.mc_rip, uc->uc_mcontext.mc_rbp);
#elif __FreeBSD__ && __i386__
    SETUP_FRAME(&uc->uc_mcontext.mc_eip, uc->uc_mcontext.mc_ebp);
#elif __NetBSD__
    // NetBSD has those portable defines. Nice!
    SETUP_FRAME(&_UC_MACHINE_PC(uc), _UC_MACHINE_FP(uc));
#elif defined(HAVE_GETPC)
    // So if we're dealing with architecture that doesn't belong to
    // one of cases above, we still have plenty more cases supported
    // by pc_from_ucontext facility we have for cpu profiler. We'll
    // get top-most instruction pointer from context, and rest will be
    // grabbed by frame pointer unwinding (with skipping active).
    //
    // It is a bit of a guess, but it works for x86 (makes
    // stacktrace_unittest ucontext test pass). Main idea is skip
    // count we have will skip just past 'sigreturn' trampoline or
    // whatever OS has. And those tend to be built without frame
    // pointers, which causes last "skipping" step to skip past the
    // frame we need. Also, this is how our CPU profiler is built. It
    // always places "pc from ucontext" first and then if necessary
    // deduplicates it from backtrace.

    result[0] = GetPC(*uc);
    if (result[0] == nullptr) {
      // This OS/HW combo actually lacks known way to extract PC.
      ucp = nullptr;
    }
#else
    ucp = nullptr;
#endif

#undef SETUP_FRAME
  }
#elif !IS_WITH_CONTEXT
  void * const ucp = nullptr;
#endif  // IS_WITH_CONTEXT

  constexpr bool UnsafeAccesses = (TCMALLOC_UNSAFE_GENERIC_FP_STACKTRACE != 0);

  if (ucp && !initial_pc) {
    // we're dealing with architecture that doesn't have proper ucontext integration
    n = stacktrace_generic_fp::capture(
      result + 1, max_depth - 1, skip_count,
      initial_frame, initial_pc, sizes);
    n++;
  } else {
    n = stacktrace_generic_fp::capture(
      result, max_depth, skip_count,
      initial_frame, initial_pc, sizes);
  }

  if (n > 0) {
    // make sure we don't tail-call capture
    (void)*(const_cast(result));
  }

  return n;
}
gperftools-gperftools-2.18/src/stacktrace_impl_setup-inl.h000066400000000000000000000075031513545575200241400ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// NOTE: this is NOT to be #include-d normally. It's internal
// implementation detail of stacktrace.cc
//

// Copyright (c) 2014, gperftools Contributors.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Aliaksey Kandratsenka 
//
//  based on stacktrace.cc and stacktrace_config.h by Sanjay Ghemawat
//  and Paul Pluzhnikov from Google Inc

#define SIS_CONCAT2(a, b) a##b
#define SIS_CONCAT(a, b) SIS_CONCAT2(a,b)

#define SIS_STRINGIFY(a) SIS_STRINGIFY2(a)
#define SIS_STRINGIFY2(a) #a

#define IS_STACK_FRAMES 0
#define IS_WITH_CONTEXT 0
#define GET_STACK_TRACE_OR_FRAMES \
  ATTRIBUTE_NOINLINE SIS_CONCAT(GetStackTrace_, GST_SUFFIX)(void **result, int max_depth, int skip_count)
#include STACKTRACE_INL_HEADER
#undef IS_STACK_FRAMES
#undef IS_WITH_CONTEXT
#undef GET_STACK_TRACE_OR_FRAMES

#define IS_STACK_FRAMES 1
#define IS_WITH_CONTEXT 0
#define GET_STACK_TRACE_OR_FRAMES \
  ATTRIBUTE_NOINLINE SIS_CONCAT(GetStackFrames_, GST_SUFFIX)(void **result, int *sizes, int max_depth, int skip_count)
#include STACKTRACE_INL_HEADER
#undef IS_STACK_FRAMES
#undef IS_WITH_CONTEXT
#undef GET_STACK_TRACE_OR_FRAMES

#define IS_STACK_FRAMES 0
#define IS_WITH_CONTEXT 1
#define GET_STACK_TRACE_OR_FRAMES \
  ATTRIBUTE_NOINLINE SIS_CONCAT(GetStackTraceWithContext_, GST_SUFFIX)(void **result, int max_depth, \
                                                                       int skip_count, const void *ucp)
#include STACKTRACE_INL_HEADER
#undef IS_STACK_FRAMES
#undef IS_WITH_CONTEXT
#undef GET_STACK_TRACE_OR_FRAMES

#define IS_STACK_FRAMES 1
#define IS_WITH_CONTEXT 1
#define GET_STACK_TRACE_OR_FRAMES \
  ATTRIBUTE_NOINLINE SIS_CONCAT(GetStackFramesWithContext_, GST_SUFFIX)(void **result, int *sizes, int max_depth, \
                                                                        int skip_count, const void *ucp)
#include STACKTRACE_INL_HEADER
#undef IS_STACK_FRAMES
#undef IS_WITH_CONTEXT
#undef GET_STACK_TRACE_OR_FRAMES

static GetStackImplementation SIS_CONCAT(impl__,GST_SUFFIX) = {
  SIS_CONCAT(GetStackFrames_, GST_SUFFIX),
  SIS_CONCAT(GetStackFramesWithContext_, GST_SUFFIX),
  SIS_CONCAT(GetStackTrace_, GST_SUFFIX),
  SIS_CONCAT(GetStackTraceWithContext_, GST_SUFFIX),
  SIS_STRINGIFY(GST_SUFFIX)
};

#undef SIS_CONCAT2
#undef SIS_CONCAT

#ifndef HAS_SOME_STACKTRACE_IMPL
#define HAS_SOME_STACKTRACE_IMPL
#endif
gperftools-gperftools-2.18/src/stacktrace_instrument-inl.h000066400000000000000000000127531513545575200241720ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2013, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Jean Lee 
// based on gcc Code-Gen-Options "-finstrument-functions" listed in
// http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html .
// Should run configure with CXXFLAGS="-finstrument-functions".

// This file is a backtrace implementation for systems :
// * The glibc implementation of backtrace() may cause a call to malloc,
//   and cause a deadlock in HeapProfiler.
// * The libunwind implementation prints no backtrace.

// The backtrace arrays are stored in "thread_back_trace" variable.
// Maybe to use thread local storage is better and should save memorys.

#ifndef BASE_STACKTRACE_INSTRUMENT_INL_H_
#define BASE_STACKTRACE_INSTRUMENT_INL_H_
// Note: this file is included into stacktrace.cc more than once.
// Anything that should only be defined once should be here:

#include 
#include 
#include 
#include 
#include "gperftools/stacktrace.h"

#define gettid() syscall(__NR_gettid)
#ifndef __x86_64__
#define MAX_THREAD (32768)
#else
#define MAX_THREAD (65536)
#endif
#define MAX_DEPTH  (30)
#define ATTRIBUTE_NOINSTRUMENT __attribute__ ((no_instrument_function))

typedef struct {
  int   stack_depth;
  void* frame[MAX_DEPTH];
}BACK_TRACE;

static BACK_TRACE thread_back_trace[MAX_THREAD];
extern "C" {
void __cyg_profile_func_enter(void *func_address,
                              void *call_site) ATTRIBUTE_NOINSTRUMENT;
void __cyg_profile_func_enter(void *func_address, void *call_site) {
  (void)func_address;

  BACK_TRACE* backtrace = thread_back_trace + gettid();
  int stack_depth = backtrace->stack_depth;
  backtrace->stack_depth = stack_depth + 1;
  if ( stack_depth >= MAX_DEPTH ) {
    return;
  }
  backtrace->frame[stack_depth] = call_site;
}

void __cyg_profile_func_exit(void *func_address,
                             void *call_site) ATTRIBUTE_NOINSTRUMENT;
void __cyg_profile_func_exit(void *func_address, void *call_site) {
  (void)func_address;
  (void)call_site;

  BACK_TRACE* backtrace = thread_back_trace + gettid();
  int stack_depth = backtrace->stack_depth;
  backtrace->stack_depth = stack_depth - 1;
  if ( stack_depth >= MAX_DEPTH ) {
    return;
  }
  backtrace->frame[stack_depth] = 0;
}
}  // extern "C"

static int cyg_backtrace(void **buffer, int size) {
  BACK_TRACE* backtrace = thread_back_trace + gettid();
  int stack_depth = backtrace->stack_depth;
  if ( stack_depth >= MAX_DEPTH ) {
    stack_depth = MAX_DEPTH;
  }
  int nSize = (size > stack_depth) ? stack_depth : size;
  for (int i = 0; i < nSize; i++) {
  buffer[i] = backtrace->frame[nSize - i - 1];
  }

  return nSize;
}

#endif  // BASE_STACKTRACE_INSTRUMENT_INL_H_


// Note: this part of the file is included several times.
// Do not put globals below.

// The following 4 functions are generated from the code below:
//   GetStack{Trace,Frames}()
//   GetStack{Trace,Frames}WithContext()
//
// These functions take the following args:
//   void** result: the stack-trace, as an array
//   int* sizes: the size of each stack frame, as an array
//               (GetStackFrames* only)
//   int max_depth: the size of the result (and sizes) array(s)
//   int skip_count: how many stack pointers to skip before storing in result
//   void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)
static int GET_STACK_TRACE_OR_FRAMES {
  static const int kStackLength = 64;
  void * stack[kStackLength];
  int size;
  memset(stack, 0, sizeof(stack));

  size = cyg_backtrace(stack, kStackLength);
  skip_count += 2;  // we want to skip the current and parent frame as well
  int result_count = size - skip_count;
  if (result_count < 0)
    result_count = 0;
  if (result_count > max_depth)
    result_count = max_depth;
  for (int i = 0; i < result_count; i++)
    result[i] = stack[i + skip_count];

#if IS_STACK_FRAMES
  // No implementation for finding out the stack frame sizes yet.
  memset(sizes, 0, sizeof(*sizes) * result_count);
#endif

  return result_count;
}
gperftools-gperftools-2.18/src/stacktrace_libgcc-inl.h000066400000000000000000000076471513545575200232130ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2016, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// This file implements backtrace capturing via libgcc's
// _Unwind_Backtrace. This generally works almost always. It will fail
// sometimes when we're trying to capture backtrace from signal
// handler (i.e. in cpu profiler) while some C++ code is throwing
// exception.

#ifndef BASE_STACKTRACE_LIBGCC_INL_H_
#define BASE_STACKTRACE_LIBGCC_INL_H_
// Note: this file is included into stacktrace.cc more than once.
// Anything that should only be defined once should be here:

extern "C" {
#include 
#include    // for memset()
}

#include 

#include "gperftools/stacktrace.h"

struct libgcc_backtrace_data {
  void **array;
  int skip;
  int pos;
  int limit;
};

static _Unwind_Reason_Code libgcc_backtrace_helper(struct _Unwind_Context *ctx,
                                                   void *_data) {
  libgcc_backtrace_data *data =
    reinterpret_cast(_data);

  if (data->skip > 0) {
    data->skip--;
    return _URC_NO_REASON;
  }

  if (data->pos >= data->limit) {
    return _URC_END_OF_STACK;
  }

  void *ip = reinterpret_cast(_Unwind_GetIP(ctx));;
  data->array[data->pos++] = ip;

  return _URC_NO_REASON;
}

#endif  // BASE_STACKTRACE_LIBGCC_INL_H_

// Note: this part of the file is included several times.
// Do not put globals below.

// The following 4 functions are generated from the code below:
//   GetStack{Trace,Frames}()
//   GetStack{Trace,Frames}WithContext()
//
// These functions take the following args:
//   void** result: the stack-trace, as an array
//   int* sizes: the size of each stack frame, as an array
//               (GetStackFrames* only)
//   int max_depth: the size of the result (and sizes) array(s)
//   int skip_count: how many stack pointers to skip before storing in result
//   void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)
static int GET_STACK_TRACE_OR_FRAMES {
  libgcc_backtrace_data data;
  data.array = result;
  // we're also skipping current and parent's frame
  data.skip = skip_count + 2;
  data.pos = 0;
  data.limit = max_depth;

  _Unwind_Backtrace(libgcc_backtrace_helper, &data);

  if (data.pos > 1 && data.array[data.pos - 1] == nullptr)
    --data.pos;

#if IS_STACK_FRAMES
  // No implementation for finding out the stack frame sizes.
  memset(sizes, 0, sizeof(*sizes) * data.pos);
#endif

  return data.pos;
}
gperftools-gperftools-2.18/src/stacktrace_libunwind-inl.h000066400000000000000000000120241513545575200237440ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Arun Sharma
//
// Produce stack trace using libunwind

#ifndef BASE_STACKTRACE_LIBINWIND_INL_H_
#define BASE_STACKTRACE_LIBINWIND_INL_H_
// Note: this file is included into stacktrace.cc more than once.
// Anything that should only be defined once should be here:

// We only need local unwinder.
#define UNW_LOCAL_ONLY

extern "C" {
#include 
#include    // for memset()
#include 
}
#include "gperftools/stacktrace.h"

#include "base/basictypes.h"
#include "base/logging.h"

// Sometimes, we can try to get a stack trace from within a stack
// trace, because libunwind can call mmap (maybe indirectly via an
// internal mmap based memory allocator), and that mmap gets trapped
// and causes a stack-trace request.  If were to try to honor that
// recursive request, we'd end up with infinite recursion or deadlock.
// Luckily, it's safe to ignore those subsequent traces.  In such
// cases, we return 0 to indicate the situation.
static __thread int recursive ATTR_INITIAL_EXEC;

#if defined(TCMALLOC_ENABLE_UNWIND_FROM_UCONTEXT) && (defined(__i386__) || defined(__x86_64__)) && defined(__GNU_LIBRARY__)
#define BASE_STACKTRACE_UNW_CONTEXT_IS_UCONTEXT 1
#endif

#endif  // BASE_STACKTRACE_LIBINWIND_INL_H_

// Note: this part of the file is included several times.
// Do not put globals below.

// The following 4 functions are generated from the code below:
//   GetStack{Trace,Frames}()
//   GetStack{Trace,Frames}WithContext()
//
// These functions take the following args:
//   void** result: the stack-trace, as an array
//   int* sizes: the size of each stack frame, as an array
//               (GetStackFrames* only)
//   int max_depth: the size of the result (and sizes) array(s)
//   int skip_count: how many stack pointers to skip before storing in result
//   void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)
static int GET_STACK_TRACE_OR_FRAMES {
  void *ip;
  int n = 0;
  unw_cursor_t cursor;
  unw_context_t uc;
#if IS_STACK_FRAMES
  unw_word_t sp = 0, next_sp = 0;
#endif

  if (recursive) {
    return 0;
  }
  ++recursive;

#if (IS_WITH_CONTEXT && defined(BASE_STACKTRACE_UNW_CONTEXT_IS_UCONTEXT))
  if (ucp) {
    uc = *(static_cast(const_cast(ucp)));
    /* this is a bit weird. profiler.cc calls us with signal's ucontext
     * yet passing us 2 as skip_count and essentially assuming we won't
     * use ucontext. */
    /* In order to fix that I'm going to assume that if ucp is
     * non-null we're asked to ignore skip_count in case we're
     * able to use ucp */
    skip_count = 0;
  } else {
    unw_getcontext(&uc);
    skip_count += 2;         // Do not include current and parent frame
  }
#else
  unw_getcontext(&uc);
  skip_count += 2;         // Do not include current and parent frame
#endif

  int ret = unw_init_local(&cursor, &uc);
  (void)ret;
  assert(ret >= 0);

  while (skip_count--) {
    if (unw_step(&cursor) <= 0) {
      goto out;
    }
#if IS_STACK_FRAMES
    if (unw_get_reg(&cursor, UNW_REG_SP, &next_sp)) {
      goto out;
    }
#endif
  }

  while (n < max_depth) {
    if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip) < 0) {
      break;
    }
#if IS_STACK_FRAMES
    sizes[n] = 0;
#endif
    result[n++] = ip;
    if (unw_step(&cursor) <= 0) {
      break;
    }
#if IS_STACK_FRAMES
    sp = next_sp;
    if (unw_get_reg(&cursor, UNW_REG_SP, &next_sp) , 0) {
      break;
    }
    sizes[n - 1] = next_sp - sp;
#endif
  }
out:
  --recursive;
  return n;
}
gperftools-gperftools-2.18/src/stacktrace_powerpc-darwin-inl.h000066400000000000000000000156221513545575200247210ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Produce stack trace.  ABI documentation reference can be found at:
// * PowerPC32 ABI: https://www.power.org/documentation/
// power-architecture-32-bit-abi-supplement-1-0-embeddedlinuxunified/
// * PowerPC64 ABI:
// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK

#ifndef BASE_STACKTRACE_POWERPC_INL_H_
#define BASE_STACKTRACE_POWERPC_INL_H_
// Note: this file is included into stacktrace.cc more than once.
// Anything that should only be defined once should be here:

#include    // for uintptr_t
#include 
#include 

// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template
static void **NextStackFrame(void **old_sp) {
  void **new_sp = (void **) *old_sp;

  // Check that the transition from frame pointer old_sp to frame
  // pointer new_sp isn't clearly bogus
  if (STRICT_UNWINDING) {
    // With the stack growing downwards, older stack frame must be
    // at a greater address that the current one.
    if (new_sp <= old_sp) return nullptr;
    // Assume stack frames larger than 100,000 bytes are bogus.
    if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
  } else {
    // In the non-strict mode, allow discontiguous stack frames.
    // (alternate-signal-stacks for example).
    if (new_sp == old_sp) return nullptr;
    // And allow frames upto about 1MB.
    if ((new_sp > old_sp)
        && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr;
  }
  if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr;
  return new_sp;
}

// This ensures that GetStackTrace stes up the Link Register properly.
void StacktracePowerPCDummyFunction() __attribute__((noinline));
void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
#endif  // BASE_STACKTRACE_POWERPC_INL_H_

// Note: this part of the file is included several times.
// Do not put globals below.

// The following 4 functions are generated from the code below:
//   GetStack{Trace,Frames}()
//   GetStack{Trace,Frames}WithContext()
//
// These functions take the following args:
//   void** result: the stack-trace, as an array
//   int* sizes: the size of each stack frame, as an array
//               (GetStackFrames* only)
//   int max_depth: the size of the result (and sizes) array(s)
//   int skip_count: how many stack pointers to skip before storing in result
//   void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)
int GET_STACK_TRACE_OR_FRAMES {
  void **sp;
  // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
  // and Darwin 8.8.1 (Tiger) use as 1.38.  This means we have to use a
  // different asm syntax.  I don't know quite the best way to discriminate
  // systems using the old as from the new one; I've gone with __APPLE__.
  // TODO(csilvers): use autoconf instead, to look for 'as --version' == 1 or 2
#if defined(__FreeBSD__) || defined(_AIX)
  __asm__ volatile ("mr %0,1" : "=r" (sp));
#else
  __asm__ volatile ("mr %0,r1" : "=r" (sp));
#endif

  // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
  // entry that holds the return address of the subroutine call (what
  // instruction we run after our function finishes).  This is the
  // same as the stack-pointer of our parent routine, which is what we
  // want here.  While the compiler will always(?) set up LR for
  // subroutine calls, it may not for leaf functions (such as this one).
  // This routine forces the compiler (at least gcc) to push it anyway.
  StacktracePowerPCDummyFunction();

#if IS_STACK_FRAMES
  // Note we do *not* increment skip_count here for the SYSV ABI.  If
  // we did, the list of stack frames wouldn't properly match up with
  // the list of return addresses.  Note this means the top pc entry
  // is probably bogus for linux/ppc (and other SYSV-ABI systems).
#else
  // The LR save area is used by the callee, so the top entry is bogus.
  skip_count++;
#endif

  int n = 0;
  while (sp && n < max_depth) {
    // The GetStackFrames routine is called when we are in some
    // informational context (the failure signal handler for example).
    // Use the non-strict unwinding rules to produce a stack trace
    // that is as complete as possible (even if it contains a few
    // bogus entries in some rare cases).
    void **next_sp = NextStackFrame(sp);

    if (skip_count > 0) {
      skip_count--;
    } else {
      // PowerPC has 3 main ABIs, which say where in the stack the
      // Link Register is.  For DARWIN and AIX (used by apple and
      // linux ppc64), it's in sp[2].  For SYSV (used by linux ppc),
      // it's in sp[1].
#if defined(__PPC64__)
      // This check is in case the compiler doesn't define _CALL_AIX/etc.
      result[n] = *(sp+2);
#elif defined(__linux)
      // This check is in case the compiler doesn't define _CALL_SYSV.
      result[n] = *(sp+1);
#endif

#if IS_STACK_FRAMES
      if (next_sp > sp) {
        sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
      } else {
        // A frame-size of 0 is used to indicate unknown frame size.
        sizes[n] = 0;
      }
#endif
      n++;
    }
    sp = next_sp;
  }
  return n;
}
gperftools-gperftools-2.18/src/stacktrace_powerpc-linux-inl.h000066400000000000000000000211331513545575200245660ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// Produce stack trace.  ABI documentation reference can be found at:
// * PowerPC32 ABI: https://www.power.org/documentation/
// power-architecture-32-bit-abi-supplement-1-0-embeddedlinuxunified/
// * PowerPC64 ABI:
// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK

#ifndef BASE_STACKTRACE_POWERPC_INL_H_
#define BASE_STACKTRACE_POWERPC_INL_H_
// Note: this file is included into stacktrace.cc more than once.
// Anything that should only be defined once should be here:

#include    // for uintptr_t
#include 
#include   // for siginfo_t
#include 
#include 

#if HAVE_SYS_UCONTEXT_H
#include 
#elif HAVE_UCONTEXT_H
#include   // for ucontext_t
#endif

// PowerPC64 Little Endian follows BE wrt. backchain, condition register,
// and LR save area, so no need to adjust the reading struct.
struct layout_ppc {
  struct layout_ppc *next;
#ifdef __PPC64__
  long condition_register;
#endif
  void *return_addr;
};

// Signal callbacks are handled by the vDSO symbol:
//
// * PowerPC64 Linux (arch/powerpc/kernel/vdso64/sigtramp.S):
//   __kernel_sigtramp_rt64
// * PowerPC32 Linux (arch/powerpc/kernel/vdso32/sigtramp.S):
//   __kernel_sigtramp32
//   __kernel_sigtramp_rt32
//
// So a backtrace may need to specially handling if the symbol readed is
// the signal trampoline.

// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template
static layout_ppc *NextStackFrame(layout_ppc *current) {
  uintptr_t old_sp = (uintptr_t)(current);
  uintptr_t new_sp = (uintptr_t)(current->next);

  // Check that the transition from frame pointer old_sp to frame
  // pointer new_sp isn't clearly bogus
  if (STRICT_UNWINDING) {
    // With the stack growing downwards, older stack frame must be
    // at a greater address that the current one.
    if (new_sp <= old_sp)
      return nullptr;
    // Assume stack frames larger than 100,000 bytes are bogus.
    if (new_sp - old_sp > 100000)
      return nullptr;
  } else {
    // In the non-strict mode, allow discontiguous stack frames.
    // (alternate-signal-stacks for example).
    if (new_sp == old_sp)
      return nullptr;
    // And allow frames upto about 1MB.
    if ((new_sp > old_sp) && (new_sp - old_sp > 1000000))
      return nullptr;
  }
  if (new_sp & (sizeof(void *) - 1))
    return nullptr;
  return current->next;
}

// This ensures that GetStackTrace stes up the Link Register properly.
void StacktracePowerPCDummyFunction() __attribute__((noinline));
void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
#endif  // BASE_STACKTRACE_POWERPC_INL_H_

// Note: this part of the file is included several times.
// Do not put globals below.

// Load instruction used on top-of-stack get.
#if defined(__PPC64__) || defined(__LP64__)
# define LOAD "ld"
#else
# define LOAD "lwz"
#endif

// The following 4 functions are generated from the code below:
//   GetStack{Trace,Frames}()
//   GetStack{Trace,Frames}WithContext()
//
// These functions take the following args:
//   void** result: the stack-trace, as an array
//   int* sizes: the size of each stack frame, as an array
//               (GetStackFrames* only)
//   int max_depth: the size of the result (and sizes) array(s)
//   int skip_count: how many stack pointers to skip before storing in result
//   void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)
static int GET_STACK_TRACE_OR_FRAMES {
  layout_ppc *current;
  int n;

  // Get the address on top-of-stack
  current = reinterpret_cast (__builtin_frame_address (0));
  // And ignore the current symbol
  current = current->next;

  StacktracePowerPCDummyFunction();

  n = 0;
  skip_count++; // skip parent's frame due to indirection in
                // stacktrace.cc

  base::VDSOSupport vdso;
  base::ElfMemImage::SymbolInfo rt_sigreturn_symbol_info;
#ifdef __PPC64__
  const void *sigtramp64_vdso = 0;
  if (vdso.LookupSymbol("__kernel_sigtramp_rt64", "LINUX_2.6.15", STT_NOTYPE,
                        &rt_sigreturn_symbol_info))
    sigtramp64_vdso = rt_sigreturn_symbol_info.address;
#else
  const void *sigtramp32_vdso = 0;
  if (vdso.LookupSymbol("__kernel_sigtramp32", "LINUX_2.6.15", STT_NOTYPE,
                        &rt_sigreturn_symbol_info))
    sigtramp32_vdso = rt_sigreturn_symbol_info.address;
  const void *sigtramp32_rt_vdso = 0;
  if (vdso.LookupSymbol("__kernel_sigtramp_rt32", "LINUX_2.6.15", STT_NOTYPE,
                        &rt_sigreturn_symbol_info))
    sigtramp32_rt_vdso = rt_sigreturn_symbol_info.address;
#endif

  while (current && n < max_depth) {

    // The GetStackFrames routine is called when we are in some
    // informational context (the failure signal handler for example).
    // Use the non-strict unwinding rules to produce a stack trace
    // that is as complete as possible (even if it contains a few
    // bogus entries in some rare cases).
    layout_ppc *next = NextStackFrame(current);
    if (skip_count > 0) {
      skip_count--;
    } else {
      result[n] = current->return_addr;
#ifdef __PPC64__
      if (sigtramp64_vdso && (sigtramp64_vdso == current->return_addr)) {
        struct signal_frame_64 {
          char dummy[128];
          ucontext_t uc;
        // We don't care about the rest, since the IP value is at 'uc' field.
        } *sigframe = reinterpret_cast(current);
        result[n] = (void*) sigframe->uc.uc_mcontext.gp_regs[PT_NIP];
      }
#else
      if (sigtramp32_vdso && (sigtramp32_vdso == current->return_addr)) {
        struct signal_frame_32 {
          char dummy[64];
          struct sigcontext sctx;
          mcontext_t mctx;
          // We don't care about the rest, since IP value is at 'mctx' field.
        } *sigframe = reinterpret_cast(current);
        result[n] = (void*) sigframe->mctx.gregs[PT_NIP];
      } else if (sigtramp32_rt_vdso && (sigtramp32_rt_vdso == current->return_addr)) {
        struct rt_signal_frame_32 {
          char dummy[64 + 16];
          siginfo_t info;
          ucontext_t uc;
          // We don't care about the rest, since IP value is at 'uc' field.A
        } *sigframe = reinterpret_cast(current);
        result[n] = (void*) sigframe->uc.uc_mcontext.uc_regs->gregs[PT_NIP];
      }
#endif

#if IS_STACK_FRAMES
      if (next > current) {
        sizes[n] = (uintptr_t)next - (uintptr_t)current;
      } else {
        // A frame-size of 0 is used to indicate unknown frame size.
        sizes[n] = 0;
      }
#endif
      n++;
    }
    current = next;
  }

  // It's possible the second-last stack frame can't return
  // (that is, it's __libc_start_main), in which case
  // the CRT startup code will have set its LR to 'nullptr'.
  if (n > 0 && result[n-1] == nullptr)
    n--;

  return n;
}
gperftools-gperftools-2.18/src/stacktrace_win32-inl.h000066400000000000000000000107711513545575200227220ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Produces a stack trace for Windows.  Normally, one could use
// stacktrace_x86-inl.h or stacktrace_x86_64-inl.h -- and indeed, that
// should work for binaries compiled using MSVC in "debug" mode.
// However, in "release" mode, Windows uses frame-pointer
// optimization, which makes getting a stack trace very difficult.
//
// There are several approaches one can take.  One is to use Windows
// intrinsics like StackWalk64.  These can work, but have restrictions
// on how successful they can be.  Another attempt is to write a
// version of stacktrace_x86-inl.h that has heuristic support for
// dealing with FPO, similar to what WinDbg does (see
// http://www.nynaeve.net/?p=97).
//
// The solution we've ended up doing is to call the undocumented
// windows function RtlCaptureStackBackTrace, which probably doesn't
// work with FPO but at least is fast, and doesn't require a symbol
// server.
//
// This code is inspired by a patch from David Vitek:
//   https://github.com/gperftools/gperftools/issues/86

#ifndef BASE_STACKTRACE_WIN32_INL_H_
#define BASE_STACKTRACE_WIN32_INL_H_
// Note: this file is included into stacktrace.cc more than once.
// Anything that should only be defined once should be here:

#include "config.h"
#include     // for GetProcAddress and GetModuleHandle
#include 

typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
    IN ULONG frames_to_skip,
    IN ULONG frames_to_capture,
    OUT PVOID *backtrace,
    OUT PULONG backtrace_hash);

// Load the function we need at static init time, where we don't have
// to worry about someone else holding the loader's lock.
static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
   (RtlCaptureStackBackTrace_Function*)
   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");

static int GetStackTrace_win32(void** result, int max_depth,
                               int skip_count) {
  if (!RtlCaptureStackBackTrace_fn) {
    // TODO(csilvers): should we log an error here?
    return 0;     // can't find a stacktrace with no function to call
  }
  return (int)RtlCaptureStackBackTrace_fn(skip_count + 3, max_depth,
                                          result, 0);
}

static int not_implemented(void) {
  assert(0 == "Not yet implemented");
  return 0;
}

static int GetStackFrames_win32(void** /* pcs */,
                                int* /* sizes */,
                                int /* max_depth */,
                                int /* skip_count */) {
  return not_implemented();
}

static int GetStackFramesWithContext_win32(void** result, int* sizes, int max_depth,
                                           int skip_count, const void *uc) {
  return not_implemented();
}

static int GetStackTraceWithContext_win32(void** result, int max_depth,
                                          int skip_count, const void *uc) {
  return not_implemented();
}


#endif  // BASE_STACKTRACE_WIN32_INL_H_
gperftools-gperftools-2.18/src/static_vars.cc000066400000000000000000000127531513545575200214560ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Ken Ashcraft 

#include 

#include "static_vars.h"

#include 
#include                           // for operator new
#ifndef _WIN32
#include                     // for pthread_atfork
#endif

#include "common.h"
#include "getenv_safe.h"       // TCMallocGetenvSafe

#include "thread_cache_ptr.h"
#include "system-alloc.h"

namespace tcmalloc {

bool Static::inited_;
SizeMap Static::sizemap_;
CentralFreeList Static::central_cache_[kClassSizesMax];
PageHeapAllocator Static::span_allocator_;
PageHeapAllocator Static::stacktrace_allocator_;
Span Static::sampled_objects_;
std::atomic Static::growth_stacks_;
StaticStorage Static::pageheap_;

void Static::InitStaticVars() {
  sizemap_.Init();
  span_allocator_.Init();
  span_allocator_.New(); // Reduce cache conflicts
  span_allocator_.New(); // Reduce cache conflicts
  stacktrace_allocator_.Init();

  for (int i = 0; i < num_size_classes(); ++i) {
    central_cache_[i].Init(i);
  }

  new (pageheap()) PageHeap(sizemap_.min_span_size_in_pages());

#if defined(ENABLE_AGGRESSIVE_DECOMMIT_BY_DEFAULT)
  const bool kDefaultAggressiveDecommit = true;
#else
  const bool kDefaultAggressiveDecommit = false;
#endif


  bool aggressive_decommit =
    tcmalloc::commandlineflags::StringToBool(
      TCMallocGetenvSafe("TCMALLOC_AGGRESSIVE_DECOMMIT"),
                         kDefaultAggressiveDecommit);

  pageheap()->SetAggressiveDecommit(aggressive_decommit);

  inited_ = true;

  DLL_Init(&sampled_objects_);
}

// These following two functions are registered via pthread_atfork to
// make sure the central_cache locks remain in a consisten state in
// the forked version of the thread. Also our OSX integration uses it
// for mi_force_lock.

void CentralCacheLockAll() NO_THREAD_SAFETY_ANALYSIS
{
  Static::pageheap_lock()->Lock();
  for (int i = 0; i < Static::num_size_classes(); ++i)
    Static::central_cache()[i].Lock();
  ThreadCachePtr::GetSlowTLSLock()->Lock();
  GetSysAllocLock()->Lock();
}

void CentralCacheUnlockAll() NO_THREAD_SAFETY_ANALYSIS
{
  GetSysAllocLock()->Unlock();
  ThreadCachePtr::GetSlowTLSLock()->Unlock();
  for (int i = 0; i < Static::num_size_classes(); ++i)
    Static::central_cache()[i].Unlock();
  Static::pageheap_lock()->Unlock();
}

void Static::InitLateMaybeRecursive() {
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(TCMALLOC_NO_ATFORK) \
  && !defined(__FreeBSD__) && !defined(_AIX)
  // OSX has it's own way of handling atfork in malloc (see
  // libc_override_osx.h).
  //
  // Windows doesn't do fork.
  //
  // FreeBSD and AIX seemingly cannot handle early pthread_atfork
  // calls. So we don't.
  //
  // For other OSes we do pthread_atfork even if standard seemingly
  // discourages pthread_atfork, asking apps to do only
  // async-signal-safe calls between fork and exec.
  //
  // We're deliberately attempting to register atfork handlers as part
  // of malloc initialization. So very early. This ensures that our
  // handler is called last and that means fork will try to grab
  // tcmalloc locks last avoiding possible issues with many other
  // locks that are held around calls to malloc. I.e. if we don't do
  // that, fork() grabbing malloc lock before such other lock would be
  // prone to deadlock, if some other thread holds other lock and
  // calls malloc.
  //
  // We still leave some way of disabling it via
  // -DTCMALLOC_NO_ATFORK. It looks like on glibc even with fully
  // static binaries malloc is really initialized very early. But I
  // can see how combination of static linking and other libc-s could
  // be less fortunate and allow some early app constructors to run
  // before malloc is ever called.

  pthread_atfork(
    CentralCacheLockAll,    // parent calls before fork
    CentralCacheUnlockAll,  // parent calls after fork
    CentralCacheUnlockAll); // child calls after fork
#endif
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/static_vars.h000066400000000000000000000116631513545575200213170ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Ken Ashcraft 
//
// Static variables shared by multiple classes.

#ifndef TCMALLOC_STATIC_VARS_H_
#define TCMALLOC_STATIC_VARS_H_

#include "config.h"

#include 

#include "base/basictypes.h"
#include "base/spinlock.h"
#include "base/static_storage.h"
#include "central_freelist.h"
#include "common.h"
#include "page_heap.h"
#include "page_heap_allocator.h"
#include "span.h"

namespace tcmalloc {

class Static {
 public:
  // Linker initialized, so this lock can be accessed at any time.
  static SpinLock* pageheap_lock() { return pageheap()->pageheap_lock(); }

  // Must be called before calling any of the accessors below.
  static void InitStaticVars();
  static void InitLateMaybeRecursive();

  // Central cache -- an array of free-lists, one per size-class.
  // We have a separate lock per free-list to reduce contention.
  static CentralFreeList* central_cache() { return central_cache_; }

  static SizeMap* sizemap() { return &sizemap_; }

  static unsigned num_size_classes() { return sizemap_.num_size_classes; }

  //////////////////////////////////////////////////////////////////////
  // In addition to the explicit initialization comment, the variables below
  // must be protected by pageheap_lock.

  // Page-level allocator.
  static PageHeap* pageheap() { return pageheap_.get(); }

  static PageHeapAllocator* span_allocator() { return &span_allocator_; }

  static PageHeapAllocator* stacktrace_allocator() {
    return &stacktrace_allocator_;
  }

  static StackTrace* growth_stacks() { return growth_stacks_.load(std::memory_order_seq_cst); }
  static void push_growth_stack(StackTrace* s) {
    ASSERT(s->depth <= kMaxStackDepth - 1);
    StackTrace* old_top = growth_stacks_.load(std::memory_order_relaxed);
    do {
      s->stack[kMaxStackDepth-1] = reinterpret_cast(old_top);
    } while (!growth_stacks_.compare_exchange_strong(
               old_top, s,
               std::memory_order_seq_cst, std::memory_order_seq_cst));
  }

  // State kept for sampled allocations (/pprof/heap support)
  static Span* sampled_objects() { return &sampled_objects_; }

  // Check if InitStaticVars() has been run.
  static bool IsInited() { return inited_; }

 private:
  ATTRIBUTE_VISIBILITY_HIDDEN static bool inited_;

  // These static variables require explicit initialization.  We cannot
  // count on their constructors to do any initialization because other
  // static variables may try to allocate memory before these variables
  // can run their constructors.

  ATTRIBUTE_VISIBILITY_HIDDEN static SizeMap sizemap_;
  ATTRIBUTE_VISIBILITY_HIDDEN static CentralFreeList central_cache_[kClassSizesMax];
  ATTRIBUTE_VISIBILITY_HIDDEN static PageHeapAllocator span_allocator_;
  ATTRIBUTE_VISIBILITY_HIDDEN static PageHeapAllocator stacktrace_allocator_;
  ATTRIBUTE_VISIBILITY_HIDDEN static Span sampled_objects_;

  // Linked list of stack traces recorded every time we allocated memory
  // from the system.  Useful for finding allocation sites that cause
  // increase in the footprint of the system.  The linked list pointer
  // is stored in trace->stack[kMaxStackDepth-1].
  ATTRIBUTE_VISIBILITY_HIDDEN static std::atomic growth_stacks_;

  ATTRIBUTE_VISIBILITY_HIDDEN static StaticStorage pageheap_;
};

}  // namespace tcmalloc

#endif  // TCMALLOC_STATIC_VARS_H_
gperftools-gperftools-2.18/src/symbolize.cc000066400000000000000000000150431513545575200211440ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2024, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "config.h"

#include "symbolize.h"

#include 
#include 
#include 

#if HAVE_CXA_DEMANGLE
#include 
#endif

#include "libbacktrace_api.h"

namespace tcmalloc {

class SymbolizePrinter {
public:
  SymbolizePrinter(backtrace_state* state, FunctionRef outcome_callback)
    : state_(state), outcome_callback_{outcome_callback} {}

  void OnePC(uintptr_t pc) {
    if (!state_) {
      DemangleAndPrint(pc, nullptr, 0, nullptr, 0);
      return;
    }

    pc_ = pc;
    want_syminfo_ = false;
    tcmalloc_backtrace_pcinfo(state_, pc,
                              &pcinfo_success,
                              &pcinfo_error,
                              this);
    if (want_syminfo_) {
      tcmalloc_backtrace_syminfo(state_, pc,
                                 &syminfo_success,
                                 &syminfo_error,
                                 this);
    }
  }

  static int pcinfo_success(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) {
    auto printer = static_cast(data);
    if (function == nullptr) {
      printer->want_syminfo_ = true;
      return 1;
    }

    printer->DemangleAndPrint(pc, filename, lineno, function, 0);

    return 0;
  }

  static void pcinfo_error(void* data, const char* msg, int errnum) {
    fprintf(stderr, "symbolization step failed (errnum=%d): %s\n", errnum, msg);

    auto printer = static_cast(data);
    printer->want_syminfo_ = true;
  }

  static void syminfo_success(void* data, uintptr_t pc, const char* symname, uintptr_t symval, uintptr_t symsize) {
    static_cast(data)->DemangleAndPrint(pc, nullptr, 0, symname, symval);
  }

  static void syminfo_error(void* data, const char* msg, int errnum) {
    fprintf(stderr, "symbolization syminfo step failed (errnum=%d): %s\n", errnum, msg);
    auto printer = static_cast(data);
    printer->DemangleAndPrint(printer->pc_, nullptr, 0, nullptr, 0);
  }

  void DemangleAndPrint(uintptr_t pc, const char* filename, int lineno, const char* function, uintptr_t symval) {
    char* demangled = nullptr;

#if HAVE_CXA_DEMANGLE
    size_t length;
    int status = -1;
    if (function != nullptr) {
      demangled = __cxxabiv1::__cxa_demangle(function, nullptr, &length, &status);
      if (status != 0) {
        free(demangled);
        demangled = nullptr;
      }
    }
#endif

    SymbolizeOutcome outcome;
    outcome.pc = pc;
    outcome.function = demangled ? demangled : function;
    outcome.original_function = function;
    outcome.filename = filename;
    outcome.lineno = lineno;
    outcome.symval = symval;

    outcome_callback_(outcome);

    free(demangled);
  }

private:
  backtrace_state* const state_;
  FunctionRef const outcome_callback_;

  uintptr_t pc_{};
  bool want_syminfo_;
};

SymbolizerAPI::SymbolizerAPI(FunctionRef *callback)
  : callback_(callback),
    // note, we create fresh un-threaded backtrace state which we
    // "dispose" at the end. This is contrary to libbacktrace's normal
    // recommendations.
    state_(tcmalloc_backtrace_create_state(nullptr, /*threaded = */0, nullptr, nullptr)) {}

void SymbolizerAPI::Add(uintptr_t addr) const {
  SymbolizePrinter{state_, *callback_}.OnePC(addr);
}

SymbolizerAPI::~SymbolizerAPI() {
  tcmalloc_backtrace_dispose_state(state_);
}

void DumpStackTraceToStderr(void * const *stack, int stack_depth,
                            bool want_symbolize, std::string_view line_prefix) {
  if (!want_symbolize) {
    for (int i = 0; i < stack_depth; i++) {
      fprintf(stderr,"%.*s%p\n",
              (int)line_prefix.size(), line_prefix.data(),
              stack[i]);
    }
    return;
  }

  SymbolizerAPI::With(
    [&] (const SymbolizerAPI& api) {
      for (int i = 0; i < stack_depth; i++) {
        api.Add(reinterpret_cast(stack[i]) - 1);
      }
    },
    [&] (const SymbolizeOutcome& o) {
      if (o.filename != nullptr) {
        // We assume that function name is not blank in this case.
        fprintf(stderr, "%.*s%p %s %s:%d\n",
                (int)line_prefix.size(), line_prefix.data(),
                reinterpret_cast(o.pc),
                o.function,
                o.filename, o.lineno);
      } else if (o.function == nullptr) {
        fprintf(stderr, "%.*s%p\n",
                (int)line_prefix.size(), line_prefix.data(),
                reinterpret_cast(o.pc));
      } else if (o.symval != 0) {
        fprintf(stderr, "%.*s%p %s + %zu\n",
                (int)line_prefix.size(), line_prefix.data(),
                reinterpret_cast(o.pc),
                o.function, o.pc - o.symval);
      } else {
        fprintf(stderr, "%.*s%p %s\n",
                (int)line_prefix.size(), line_prefix.data(),
                reinterpret_cast(o.pc),
                o.function);
      }
    });
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/symbolize.h000066400000000000000000000052661513545575200210140ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2024, gperftools Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef TCMALLOC_SYMBOLIZE_H_
#define TCMALLOC_SYMBOLIZE_H_

#include "config.h"

#include 

#include 

#include "base/basictypes.h"
#include "base/function_ref.h"

extern "C" {
  struct backtrace_state;
}

namespace tcmalloc {

ATTRIBUTE_VISIBILITY_HIDDEN
void DumpStackTraceToStderr(
  void * const *stack, int stack_depth, bool want_symbolize,
  std::string_view line_prefix);

struct SymbolizeOutcome {
  uintptr_t pc;
  const char* function;
  const char* filename;
  int lineno;
  uintptr_t symval;
  const char* original_function;
};

class ATTRIBUTE_VISIBILITY_HIDDEN SymbolizerAPI {
public:
  explicit SymbolizerAPI(FunctionRef *callback);
  ~SymbolizerAPI();

  static void With(FunctionRef body,
                   FunctionRef callback) {
    body(SymbolizerAPI{&callback});
  }

  void Add(uintptr_t addr) const;
private:
  FunctionRef *callback_;
  backtrace_state* state_;
};

}  // namespace tcmalloc

#endif  // TCMALLOC_SYMBOLIZE_H_
gperftools-gperftools-2.18/src/system-alloc.cc000066400000000000000000000401601513545575200215410ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat

#include 

#include                       // for EAGAIN, errno
#include                       // for open, O_RDWR
#include                      // for size_t, ptrdiff_t
#include                      // for uintptr_t, intptr_t

#ifdef HAVE_MMAP
#include                    // for munmap, mmap, MADV_DONTNEED, etc
#endif
#ifdef HAVE_UNISTD_H
#include                      // for sbrk, getpagesize, off_t
#endif

#include 

#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "base/spinlock.h"              // for SpinLockHolder, SpinLock, etc
#include "base/static_storage.h"
#include "common.h"
#include "internal_logging.h"

// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
// form of the name instead.
#ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
#endif

// Linux added support for MADV_FREE in 4.5 but we aren't ready to use it
// yet. Among other things, using compile-time detection leads to poor
// results when compiling on a system with MADV_FREE and running on a
// system without it. See https://github.com/gperftools/gperftools/issues/780.
#if defined(__linux__) && defined(MADV_FREE) && !defined(TCMALLOC_USE_MADV_FREE)
# undef MADV_FREE
#endif

// MADV_FREE is specifically designed for use by malloc(), but only
// FreeBSD supports it; in linux we fall back to the somewhat inferior
// MADV_DONTNEED.
#if !defined(MADV_FREE) && defined(MADV_DONTNEED)
# define MADV_FREE  MADV_DONTNEED
#endif

// Set kDebugMode mode so that we can have use C++ conditionals
// instead of preprocessor conditionals.
#ifdef NDEBUG
static const bool kDebugMode = false;
#else
static const bool kDebugMode = true;
#endif

// Check that no bit is set at position ADDRESS_BITS or higher.
static bool CheckAddressBits(uintptr_t ptr) {
  bool always_ok = (kAddressBits == 8 * sizeof(void*));
  // this is a bit insane but otherwise we get compiler warning about
  // shifting right by word size even if this code is dead :(
  int shift_bits = always_ok ? 0 : kAddressBits;
  return always_ok || ((ptr >> shift_bits) == 0);
}

static_assert(kAddressBits <= 8 * sizeof(void*),
              "address bits larger than pointer size");

static SpinLock spinlock;

#if defined(HAVE_MMAP) || defined(MADV_FREE)
// Page size is initialized on demand (only needed for mmap-based allocators)
static size_t pagesize = 0;
#endif

// The current system allocator
SysAllocator* tcmalloc_sys_alloc;

// Number of bytes taken from system.
size_t TCMalloc_SystemTaken = 0;

DEFINE_bool(malloc_skip_sbrk,
            EnvToBool("TCMALLOC_SKIP_SBRK", false),
            "Whether sbrk can be used to obtain memory.");
DEFINE_bool(malloc_skip_mmap,
            EnvToBool("TCMALLOC_SKIP_MMAP", false),
            "Whether mmap can be used to obtain memory.");
DEFINE_bool(malloc_disable_memory_release,
            EnvToBool("TCMALLOC_DISABLE_MEMORY_RELEASE", false),
            "Whether MADV_FREE/MADV_DONTNEED should be used"
            " to return unused memory to the system.");

// static allocators
class SbrkSysAllocator : public SysAllocator {
public:
  SbrkSysAllocator() : SysAllocator() {
  }
  void* Alloc(size_t size, size_t *actual_size, size_t alignment);
};
static tcmalloc::StaticStorage sbrk_space;

class MmapSysAllocator : public SysAllocator {
public:
  MmapSysAllocator() : SysAllocator() {
  }
  void* Alloc(size_t size, size_t *actual_size, size_t alignment);
private:
  uintptr_t hint_ = 0;
};
static tcmalloc::StaticStorage mmap_space;

class DefaultSysAllocator : public SysAllocator {
 public:
  DefaultSysAllocator() : SysAllocator() {
    for (int i = 0; i < kMaxAllocators; i++) {
      failed_[i] = true;
      allocs_[i] = nullptr;
      names_[i] = nullptr;
    }
  }
  void SetChildAllocator(SysAllocator* alloc, unsigned int index,
                         const char* name) {
    if (index < kMaxAllocators && alloc != nullptr) {
      allocs_[index] = alloc;
      failed_[index] = false;
      names_[index] = name;
    }
  }
  void* Alloc(size_t size, size_t *actual_size, size_t alignment);

 private:
  static const int kMaxAllocators = 2;
  bool failed_[kMaxAllocators];
  SysAllocator* allocs_[kMaxAllocators];
  const char* names_[kMaxAllocators];
};
static tcmalloc::StaticStorage default_space;
static const char sbrk_name[] = "SbrkSysAllocator";
static const char mmap_name[] = "MmapSysAllocator";

void* SbrkSysAllocator::Alloc(size_t size, size_t *actual_size,
                              size_t alignment) {
#if !defined(HAVE_SBRK) || defined(__UCLIBC__)
  return nullptr;
#else
  // Check if we should use sbrk allocation.
  // FLAGS_malloc_skip_sbrk starts out as false (its uninitialized
  // state) and eventually gets initialized to the specified value.  Note
  // that this code runs for a while before the flags are initialized.
  // That means that even if this flag is set to true, some (initial)
  // memory will be allocated with sbrk before the flag takes effect.
  if (FLAGS_malloc_skip_sbrk) {
    return nullptr;
  }

  // sbrk will release memory if passed a negative number, so we do
  // a strict check here
  if (static_cast(size + alignment) < 0) return nullptr;

  // This doesn't overflow because TCMalloc_SystemAlloc has already
  // tested for overflow at the alignment boundary.
  size = ((size + alignment - 1) / alignment) * alignment;

  // "actual_size" indicates that the bytes from the returned pointer
  // p up to and including (p + actual_size - 1) have been allocated.
  if (actual_size) {
    *actual_size = size;
  }

  // Check that we we're not asking for so much more memory that we'd
  // wrap around the end of the virtual address space.  (This seems
  // like something sbrk() should check for us, and indeed opensolaris
  // does, but glibc does not:
  //    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(sbrk(0)) + size < size) {
    return nullptr;
  }

  void* result = sbrk(size);
  if (result == reinterpret_cast(-1)) {
    return nullptr;
  }

  // Is it aligned?
  uintptr_t ptr = reinterpret_cast(result);
  if ((ptr & (alignment-1)) == 0)  return result;

  // Try to get more memory for alignment
  size_t extra = alignment - (ptr & (alignment-1));
  void* r2 = sbrk(extra);
  if (reinterpret_cast(r2) == (ptr + size)) {
    // Contiguous with previous result
    return reinterpret_cast(ptr + extra);
  }

  // Give up and ask for "size + alignment - 1" bytes so
  // that we can find an aligned region within it.
  result = sbrk(size + alignment - 1);
  if (result == reinterpret_cast(-1)) {
    return nullptr;
  }
  ptr = reinterpret_cast(result);
  if ((ptr & (alignment-1)) != 0) {
    ptr += alignment - (ptr & (alignment-1));
  }
  return reinterpret_cast(ptr);
#endif  // HAVE_SBRK
}

void* MmapSysAllocator::Alloc(size_t size, size_t *actual_size,
                              size_t alignment) {
#ifndef HAVE_MMAP
  return nullptr;
#else
  // Check if we should use mmap allocation.
  // FLAGS_malloc_skip_mmap starts out as false (its uninitialized
  // state) and eventually gets initialized to the specified value.  Note
  // that this code runs for a while before the flags are initialized.
  // Chances are we never get here before the flags are initialized since
  // sbrk is used until the heap is exhausted (before mmap is used).
  if (FLAGS_malloc_skip_mmap) {
    return nullptr;
  }

  // Enforce page alignment
  if (pagesize == 0) pagesize = getpagesize();
  if (alignment < pagesize) alignment = pagesize;
  size_t aligned_size = ((size + alignment - 1) / alignment) * alignment;
  if (aligned_size < size) {
    return nullptr;
  }
  size = aligned_size;

  // "actual_size" indicates that the bytes from the returned pointer
  // p up to and including (p + actual_size - 1) have been allocated.
  if (actual_size) {
    *actual_size = size;
  }

  if (hint_ && hint_ + size > size && (hint_ & (alignment - 1)) == 0) {
    // We try to 'continue' previous mapping. But we first check that
    // alignment requirements are met and that it won't overflow
    // address space.
    void* result = mmap(reinterpret_cast(hint_), size,
                        PROT_READ|PROT_WRITE,
                        MAP_PRIVATE|MAP_ANONYMOUS,
                        -1, 0);

    uintptr_t ptr = reinterpret_cast(result);

    // If the new mapping (even if at different address than hint
    // passed) requested alignment, then we return it.
    if ((ptr & (alignment - 1)) == 0) {
      hint_ = ptr + size;
      return result;
    }

    // Otherwise, we unmap and run "full" logic that is able to align
    // to arbitrary alignment. And that doesn't use hint.
    munmap(result, size);
  }

  // Ask for extra memory if alignment > pagesize
  size_t extra = 0;
  if (alignment > pagesize) {
    extra = alignment - pagesize;
  }

  // Note: size + extra does not overflow since:
  //            size + alignment < (1<(MAP_FAILED)) {
    return nullptr;
  }

  // Adjust the return memory so it is aligned
  uintptr_t ptr = reinterpret_cast(result);
  size_t adjust = 0;
  if ((ptr & (alignment - 1)) != 0) {
    adjust = alignment - (ptr & (alignment - 1));
  }

  // Return the unused memory to the system
  if (adjust > 0) {
    munmap(reinterpret_cast(ptr), adjust);
  }
  if (adjust < extra) {
    munmap(reinterpret_cast(ptr + adjust + size), extra - adjust);
  }

  ptr += adjust;
  hint_ = ptr + size;
  return reinterpret_cast(ptr);
#endif  // HAVE_MMAP
}

void* DefaultSysAllocator::Alloc(size_t size, size_t *actual_size,
                                 size_t alignment) {
  for (int i = 0; i < kMaxAllocators; i++) {
    if (!failed_[i] && allocs_[i] != nullptr) {
      void* result = allocs_[i]->Alloc(size, actual_size, alignment);
      if (result != nullptr) {
        return result;
      }
      failed_[i] = true;
    }
  }
  // After both failed, reset "failed_" to false so that a single failed
  // allocation won't make the allocator never work again.
  for (int i = 0; i < kMaxAllocators; i++) {
    failed_[i] = false;
  }
  return nullptr;
}

ATTRIBUTE_WEAK ATTRIBUTE_NOINLINE
SysAllocator *tc_get_sysalloc_override(SysAllocator *def)
{
  return def;
}

static bool system_alloc_inited = false;
void InitSystemAllocators(void) {
  MmapSysAllocator *mmap = mmap_space.Construct();
  SbrkSysAllocator *sbrk = sbrk_space.Construct();

  // In 64-bit debug mode, place the mmap allocator first since it
  // allocates pointers that do not fit in 32 bits and therefore gives
  // us better testing of code's 64-bit correctness.  It also leads to
  // less false negatives in heap-checking code.  (Numbers are less
  // likely to look like pointers and therefore the conservative gc in
  // the heap-checker is less likely to misinterpret a number as a
  // pointer).
  DefaultSysAllocator *sdef = default_space.Construct();
  bool want_mmap = kDebugMode && (sizeof(void*) > 4);
  if (want_mmap) {
    sdef->SetChildAllocator(mmap, 0, mmap_name);
    sdef->SetChildAllocator(sbrk, 1, sbrk_name);
  } else {
    sdef->SetChildAllocator(sbrk, 0, sbrk_name);
    sdef->SetChildAllocator(mmap, 1, mmap_name);
  }

  tcmalloc_sys_alloc = tc_get_sysalloc_override(sdef);
}

void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
                           size_t alignment) {
  // Discard requests that overflow
  if (size + alignment < size) return nullptr;

  SpinLockHolder lock_holder(&spinlock);

  if (!system_alloc_inited) {
    InitSystemAllocators();
    system_alloc_inited = true;
  }

  // Enforce minimum alignment
  if (alignment < sizeof(MemoryAligner)) alignment = sizeof(MemoryAligner);

  size_t actual_size_storage;
  if (actual_size == nullptr) {
    actual_size = &actual_size_storage;
  }

  void* result = tcmalloc_sys_alloc->Alloc(size, actual_size, alignment);
  if (result != nullptr) {
    CHECK_CONDITION(
      CheckAddressBits(reinterpret_cast(result) + *actual_size - 1));
    TCMalloc_SystemTaken += *actual_size;
  }
  return result;
}

bool TCMalloc_SystemRelease(void* start, size_t length) {
#if defined(FREE_MMAP_PROT_NONE) && defined(HAVE_MMAP) || defined(MADV_FREE)
  if (FLAGS_malloc_disable_memory_release) return false;
  if (pagesize == 0) pagesize = getpagesize();
  const size_t pagemask = pagesize - 1;

  size_t new_start = reinterpret_cast(start);
  size_t end = new_start + length;
  size_t new_end = end;

  // Round up the starting address and round down the ending address
  // to be page aligned:
  new_start = (new_start + pagesize - 1) & ~pagemask;
  new_end = new_end & ~pagemask;

  ASSERT((new_start & pagemask) == 0);
  ASSERT((new_end & pagemask) == 0);
  ASSERT(new_start >= reinterpret_cast(start));
  ASSERT(new_end <= end);

  if (new_end > new_start) {
    bool result, retry;
    do {
#if defined(FREE_MMAP_PROT_NONE) && defined(HAVE_MMAP)
      // mmap PROT_NONE is similar to munmap by freeing backing pages by
      // physical memory except using MAP_FIXED keeps virtual memory range
      // reserved to be remapped back later
      void* ret = mmap(reinterpret_cast(new_start), new_end - new_start,
          PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);

      result = ret != MAP_FAILED;
#else
      int ret = madvise(reinterpret_cast(new_start),
          new_end - new_start, MADV_FREE);

      result = ret != -1;
#endif
      retry = errno == EAGAIN;
    } while (!result && retry);

    return result;
  }
#endif 
  return false;
}

void TCMalloc_SystemCommit(void* start, size_t length) {
#if defined(FREE_MMAP_PROT_NONE) && defined(HAVE_MMAP)
  // remaping as MAP_FIXED to same address assuming span size did not change 
  // since last TCMalloc_SystemRelease
  mmap(start, length, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
       -1, 0);
#else
  // Nothing to do here.  TCMalloc_SystemRelease does not alter pages
  // such that they need to be re-committed before they can be used by the
  // application.
#endif
}

SpinLock* GetSysAllocLock() {
  return &spinlock;
}
gperftools-gperftools-2.18/src/system-alloc.h000066400000000000000000000100441513545575200214010ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// Routine that uses sbrk/mmap to allocate memory from the system.
// Useful for implementing malloc.

#ifndef TCMALLOC_SYSTEM_ALLOC_H_
#define TCMALLOC_SYSTEM_ALLOC_H_

#include 
#include                      // for size_t

#include "base/basictypes.h"
#include "base/spinlock.h"

class SysAllocator;

// REQUIRES: "alignment" is a power of two or "0" to indicate default alignment
//
// Allocate and return "N" bytes of zeroed memory.
//
// If actual_bytes is nullptr then the returned memory is exactly the
// requested size.  If actual bytes is non-nullptr then the allocator
// may optionally return more bytes than asked for (i.e. return an
// entire "huge" page if a huge page allocator is in use).
//
// The returned pointer is a multiple of "alignment" if non-zero. The
// returned pointer will always be aligned suitably for holding a
// void*, double, or size_t. In addition, if this platform defines
// CACHELINE_ALIGNED, the return pointer will always be cacheline
// aligned.
//
// Returns nullptr when out of memory.
extern PERFTOOLS_DLL_DECL
void* TCMalloc_SystemAlloc(size_t bytes, size_t *actual_bytes,
			   size_t alignment = 0);

// This call is a hint to the operating system that the pages
// contained in the specified range of memory will not be used for a
// while, and can be released for use by other processes or the OS.
// Pages which are released in this way may be destroyed (zeroed) by
// the OS.  The benefit of this function is that it frees memory for
// use by the system, the cost is that the pages are faulted back into
// the address space next time they are touched, which can impact
// performance.  (Only pages fully covered by the memory region will
// be released, partial pages will not.)
//
// Returns false if release failed or not supported.
extern PERFTOOLS_DLL_DECL
bool TCMalloc_SystemRelease(void* start, size_t length);

// Called to ressurect memory which has been previously released
// to the system via TCMalloc_SystemRelease.  An attempt to
// commit a page that is already committed does not cause this
// function to fail.
extern PERFTOOLS_DLL_DECL
void TCMalloc_SystemCommit(void* start, size_t length);

// The current system allocator.
extern PERFTOOLS_DLL_DECL SysAllocator* tcmalloc_sys_alloc;

// Number of bytes taken from system.
extern PERFTOOLS_DLL_DECL size_t TCMalloc_SystemTaken;

ATTRIBUTE_VISIBILITY_HIDDEN
SpinLock* GetSysAllocLock();

#endif /* TCMALLOC_SYSTEM_ALLOC_H_ */
gperftools-gperftools-2.18/src/tcmalloc.cc000066400000000000000000002370711513545575200207340ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 
//
// A malloc that uses a per-thread cache to satisfy small malloc requests.
// (The time for malloc/free of a small object drops from 300 ns to 50 ns.)
//
// See docs/tcmalloc.html for a high-level
// description of how this malloc works.
//
// SYNCHRONIZATION
//  1. The thread-specific lists are accessed without acquiring any locks.
//     This is safe because each such list is only accessed by one thread.
//  2. We have a lock per central free-list, and hold it while manipulating
//     the central free list for a particular size.
//  3. The central page allocator is protected by "pageheap_lock".
//  4. The pagemap (which maps from page-number to descriptor),
//     can be read without holding any locks, and written while holding
//     the "pageheap_lock".
//  5. To improve performance, a subset of the information one can get
//     from the pagemap is cached in a data structure, pagemap_cache_,
//     that atomically reads and writes its entries.  This cache can be
//     read and written without locking.
//
//     This multi-threaded access to the pagemap is safe for fairly
//     subtle reasons.  We basically assume that when an object X is
//     allocated by thread A and deallocated by thread B, there must
//     have been appropriate synchronization in the handoff of object
//     X from thread A to thread B.  The same logic applies to pagemap_cache_.
//
// THE PAGEID-TO-SIZECLASS CACHE
// Hot PageID-to-sizeclass mappings are held by pagemap_cache_.  If this cache
// returns 0 for a particular PageID then that means "no information," not that
// the sizeclass is 0.  The cache may have stale information for pages that do
// not hold the beginning of any free()'able object.  Staleness is eliminated
// in Populate() for pages with sizeclass > 0 objects, and in do_malloc() and
// do_memalign() for all other relevant pages.
//
// PAGEMAP
// -------
// Page map contains a mapping from page id to Span.
//
// If Span s occupies pages [p..q],
//      pagemap[p] == s
//      pagemap[q] == s
//      pagemap[p+1..q-1] are undefined
//      pagemap[p-1] and pagemap[q+1] are defined:
//         nullptr if the corresponding page is not yet in the address space.
//         Otherwise it points to a Span.  This span may be free
//         or allocated.  If free, it is in one of pageheap's freelist.
//
// TODO: Bias reclamation to larger addresses
// TODO: Better testing
//
// 9/28/2003 (new page-level allocator replaces ptmalloc2):
// * malloc/free of small objects goes from ~300 ns to ~50 ns.
// * allocation of a reasonably complicated struct
//   goes from about 1100 ns to about 300 ns.

#include "config.h"
// At least for gcc on Linux/i386 and Linux/amd64 not adding throw()
// to tc_xxx functions actually ends up generating better code.
#define PERFTOOLS_NOTHROW
#include 

#include                       // for ENOMEM, EINVAL, errno
#include 
#include                      // for size_t
#include                      // for getenv
#include                      // for strcmp, memset, strlen, etc
#ifdef HAVE_UNISTD_H
#include                      // for getpagesize, write, etc
#endif
#include                     // for max, min
#include                        // for numeric_limits
#include                           // for nothrow_t (ptr only), etc
#include                        // for vector

#include 
#include          // for MallocHook
#include 
#include "base/basictypes.h"            // for int64
#include "base/commandlineflags.h"      // for RegisterFlagValidator, etc
#include "base/dynamic_annotations.h"   // for RunningOnValgrind
#include "base/spinlock.h"              // for SpinLockHolder
#include "central_freelist.h"
#include "common.h"            // for StackTrace, kPageShift, etc
#include "internal_logging.h"  // for ASSERT, TCMalloc_Printer, etc
#include "linked_list.h"       // for SLL_SetNext
#include "malloc_hook-inl.h"       // for tcmalloc::InvokeNewHook, etc
#include "page_heap.h"         // for PageHeap, PageHeap::Stats
#include "page_heap_allocator.h"  // for PageHeapAllocator
#include "span.h"              // for Span, DLL_Prepend, etc
#include "stack_trace_table.h"  // for StackTraceTable
#include "static_vars.h"       // for Static
#include "system-alloc.h"      // for DumpSystemAllocatorStats, etc
#include "tcmalloc_guard.h"    // for TCMallocGuard
#include "thread_cache.h"      // for ThreadCache
#include "thread_cache_ptr.h"

#include "malloc_backtrace.h"
#include "maybe_emergency_malloc.h" // IWYU pragma: keep
#include "testing_portal.h"

#if (defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)) && !defined(WIN32_OVERRIDE_ALLOCATORS)
# define WIN32_DO_PATCHING 1
#endif

// Some windows file somewhere (at least on cygwin) #define's small (!)
#undef small

#include "libc_override.h"

using tcmalloc::kCrash;
using tcmalloc::Log;
using tcmalloc::PageHeap;
using tcmalloc::Span;
using tcmalloc::StackTrace;
using tcmalloc::Static;
using tcmalloc::ThreadCache;
using tcmalloc::ThreadCachePtr;

using tcmalloc::TestingPortal;

DECLARE_double(tcmalloc_release_rate);
DECLARE_int64(tcmalloc_heap_limit_mb);

// Those common architectures are known to be safe w.r.t. aliasing function
// with "extra" unused args to function with fewer arguments (e.g.
// tc_delete_nothrow being aliased to tc_delete).
//
// Benefit of aliasing is relatively moderate. It reduces instruction
// cache pressure a bit (not relevant for largely unused
// tc_delete_nothrow, but is potentially relevant for
// tc_delete_aligned (or sized)). It also used to be the case that gcc
// 5+ optimization for merging identical functions kicked in and
// "screwed" one of the otherwise identical functions with extra
// jump. I am not able to reproduce that anymore.
#if !defined(__i386__) && !defined(__x86_64__) && \
    !defined(__ppc__) && !defined(__PPC__) && \
    !defined(__aarch64__) && !defined(__mips__) && !defined(__arm__) && !defined(__loongarch64)
#undef TCMALLOC_NO_ALIASES
#define TCMALLOC_NO_ALIASES
#endif

#if defined(__GNUC__) && defined(__ELF__) && !defined(TCMALLOC_NO_ALIASES)
#define TC_ALIAS(name) __attribute__((alias(#name)))
#endif

extern "C" {
  ATTRIBUTE_NOINLINE void* tc_malloc(size_t size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_free(void* ptr) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_free_sized(void* ptr, size_t size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_free_aligned_sized(void* ptr, size_t align, size_t size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void* tc_realloc(void* ptr, size_t size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void* tc_calloc(size_t nmemb, size_t size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_cfree(void* ptr) PERFTOOLS_NOTHROW;

  ATTRIBUTE_NOINLINE void* tc_memalign(size_t __alignment, size_t __size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE int tc_posix_memalign(void** ptr, size_t align, size_t size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void* tc_valloc(size_t __size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void* tc_pvalloc(size_t __size) PERFTOOLS_NOTHROW;

  ATTRIBUTE_NOINLINE void tc_malloc_stats(void) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE int tc_mallopt(int cmd, int value) PERFTOOLS_NOTHROW;
#if GPERFTOOLS_HAS_MALLINFO
  ATTRIBUTE_NOINLINE struct mallinfo tc_mallinfo(void) PERFTOOLS_NOTHROW;
#endif
#ifdef GPERFTOOLS_HAS_MALLINFO2
  ATTRIBUTE_NOINLINE struct mallinfo2 tc_mallinfo2(void) PERFTOOLS_NOTHROW;
#endif

  ATTRIBUTE_NOINLINE void* tc_new(size_t size);
  ATTRIBUTE_NOINLINE void tc_delete(void* p) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_delete_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void* tc_newarray(size_t size);
  ATTRIBUTE_NOINLINE void tc_deletearray(void* p) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_deletearray_sized(void* p, size_t size) PERFTOOLS_NOTHROW;

  // And the nothrow variants of these:
  ATTRIBUTE_NOINLINE void* tc_new_nothrow(size_t size, const std::nothrow_t&) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) PERFTOOLS_NOTHROW;
  // Surprisingly, standard C++ library implementations use a
  // nothrow-delete internally.  See, eg:
  // http://www.dinkumware.com/manuals/?manual=compleat&page=new.html
  ATTRIBUTE_NOINLINE void tc_delete_nothrow(void* ptr, const std::nothrow_t&) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_deletearray_nothrow(void* ptr, const std::nothrow_t&) PERFTOOLS_NOTHROW;

  ATTRIBUTE_NOINLINE void* tc_new_aligned(size_t size, std::align_val_t al);
  ATTRIBUTE_NOINLINE void tc_delete_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_delete_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void* tc_newarray_aligned(size_t size, std::align_val_t al);
  ATTRIBUTE_NOINLINE void tc_deletearray_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_deletearray_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;

  // And the nothrow variants of these:
  ATTRIBUTE_NOINLINE void* tc_new_aligned_nothrow(size_t size, std::align_val_t al, const std::nothrow_t&) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void* tc_newarray_aligned_nothrow(size_t size, std::align_val_t al, const std::nothrow_t&) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_delete_aligned_nothrow(void* ptr, std::align_val_t al, const std::nothrow_t&) PERFTOOLS_NOTHROW;
  ATTRIBUTE_NOINLINE void tc_deletearray_aligned_nothrow(void* ptr, std::align_val_t al, const std::nothrow_t&) PERFTOOLS_NOTHROW;

  // Some non-standard extensions that we support.

  // This is equivalent to
  //    OS X: malloc_size()
  //    glibc: malloc_usable_size()
  //    Windows: _msize()
  ATTRIBUTE_NOINLINE size_t tc_malloc_size(void* p) PERFTOOLS_NOTHROW;
}  // extern "C"

// ----------------------- IMPLEMENTATION -------------------------------

static int tc_new_mode = 0;  // See tc_set_new_mode().

// Routines such as free() and realloc() catch some erroneous pointers
// passed to them, and invoke the below when they do.  (An erroneous pointer
// won't be caught if it's within a valid span or a stale span for which
// the pagemap cache has a non-zero sizeclass.) This is a cheap (source-editing
// required) kind of exception handling for these routines.
namespace {
ATTRIBUTE_NOINLINE void InvalidFree(void* ptr) {
  if (tcmalloc::IsEmergencyPtr(ptr)) {
    tcmalloc::EmergencyFree(ptr);
    return;
  }
  Log(kCrash, __FILE__, __LINE__, "Attempt to free invalid pointer", ptr);
}

size_t InvalidGetAllocatedSize(const void* ptr) {
  if (tcmalloc::IsEmergencyPtr(ptr)) {
    return tcmalloc::EmergencyAllocatedSize(ptr);
  }
  Log(kCrash, __FILE__, __LINE__,
      "Attempt to get the size of an invalid pointer", ptr);
  return 0;
}

}  // unnamed namespace

// Extract interesting stats
struct TCMallocStats {
  uint64_t thread_bytes;      // Bytes in thread caches
  uint64_t central_bytes;     // Bytes in central cache
  uint64_t transfer_bytes;    // Bytes in central transfer cache
  uint64_t metadata_bytes;    // Bytes alloced for metadata
  PageHeap::Stats pageheap;   // Stats from page heap
};

// Get stats into "r".  Also, if class_count != nullptr, class_count[k]
// will be set to the total number of objects of size class k in the
// central cache, transfer cache, and per-thread caches. If small_spans
// is non-nullptr, it is filled.  Same for large_spans.
static void ExtractStats(TCMallocStats* r, uint64_t* class_count,
                         PageHeap::SmallSpanStats* small_spans,
                         PageHeap::LargeSpanStats* large_spans) {
  r->central_bytes = 0;
  r->transfer_bytes = 0;
  for (int cl = 0; cl < Static::num_size_classes(); ++cl) {
    const int length = Static::central_cache()[cl].length();
    const int tc_length = Static::central_cache()[cl].tc_length();
    const size_t cache_overhead = Static::central_cache()[cl].OverheadBytes();
    const size_t size = static_cast(
        Static::sizemap()->ByteSizeForClass(cl));
    r->central_bytes += (size * length) + cache_overhead;
    r->transfer_bytes += (size * tc_length);
    if (class_count) {
      // Sum the lengths of all per-class freelists, except the per-thread
      // freelists, which get counted when we call GetThreadStats(), below.
      class_count[cl] = length + tc_length;
    }

  }

  // Add stats from per-thread heaps
  r->thread_bytes = 0;
  { // scope
    SpinLockHolder h(Static::pageheap_lock());
    ThreadCache::GetThreadStats(&r->thread_bytes, class_count);
    r->metadata_bytes = tcmalloc::metadata_system_bytes();
    r->pageheap = Static::pageheap()->StatsLocked();
    if (small_spans != nullptr) {
      Static::pageheap()->GetSmallSpanStatsLocked(small_spans);
    }
    if (large_spans != nullptr) {
      Static::pageheap()->GetLargeSpanStatsLocked(large_spans);
    }
  }
}

static double PagesToMiB(uint64_t pages) {
  return (pages << kPageShift) / 1048576.0;
}

// WRITE stats to "out"
static void DumpStats(TCMalloc_Printer* out, int level) {
  TCMallocStats stats;
  uint64_t class_count[kClassSizesMax];
  PageHeap::SmallSpanStats small;
  PageHeap::LargeSpanStats large;
  if (level >= 2) {
    ExtractStats(&stats, class_count, &small, &large);
  } else {
    ExtractStats(&stats, nullptr, nullptr, nullptr);
  }

  static const double MiB = 1048576.0;

  const uint64_t virtual_memory_used = (stats.pageheap.system_bytes
                                        + stats.metadata_bytes);
  const uint64_t physical_memory_used = (virtual_memory_used
                                         - stats.pageheap.unmapped_bytes);
  const uint64_t bytes_in_use_by_app = (physical_memory_used
                                        - stats.metadata_bytes
                                        - stats.pageheap.free_bytes
                                        - stats.central_bytes
                                        - stats.transfer_bytes
                                        - stats.thread_bytes);

#ifdef TCMALLOC_SMALL_BUT_SLOW
  out->printf(
      "NOTE:  SMALL MEMORY MODEL IS IN USE, PERFORMANCE MAY SUFFER.\n");
#endif
  out->printf(
      "------------------------------------------------\n"
      "MALLOC:   %12" PRIu64 " (%7.1f MiB) Bytes in use by application\n"
      "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in page heap freelist\n"
      "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in central cache freelist\n"
      "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in transfer cache freelist\n"
      "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in thread cache freelists\n"
      "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in malloc metadata\n"
      "MALLOC:   ------------\n"
      "MALLOC: = %12" PRIu64 " (%7.1f MiB) Actual memory used (physical + swap)\n"
      "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes released to OS (aka unmapped)\n"
      "MALLOC:   ------------\n"
      "MALLOC: = %12" PRIu64 " (%7.1f MiB) Virtual address space used\n"
      "MALLOC:\n"
      "MALLOC:   %12" PRIu64 "              Spans in use\n"
      "MALLOC:   %12" PRIu64 "              Thread heaps in use\n"
      "MALLOC:   %12" PRIu64 "              Tcmalloc page size\n"
      "------------------------------------------------\n"
      "Call ReleaseFreeMemory() to release freelist memory to the OS"
      " (via madvise()).\n"
      "Bytes released to the OS take up virtual address space"
      " but no physical memory.\n",
      bytes_in_use_by_app, bytes_in_use_by_app / MiB,
      stats.pageheap.free_bytes, stats.pageheap.free_bytes / MiB,
      stats.central_bytes, stats.central_bytes / MiB,
      stats.transfer_bytes, stats.transfer_bytes / MiB,
      stats.thread_bytes, stats.thread_bytes / MiB,
      stats.metadata_bytes, stats.metadata_bytes / MiB,
      physical_memory_used, physical_memory_used / MiB,
      stats.pageheap.unmapped_bytes, stats.pageheap.unmapped_bytes / MiB,
      virtual_memory_used, virtual_memory_used / MiB,
      uint64_t(Static::span_allocator()->inuse()),
      uint64_t(ThreadCache::HeapsInUse()),
      uint64_t(kPageSize));

  if (level >= 2) {
    out->printf("------------------------------------------------\n");
    out->printf("Total size of freelists for per-thread caches,\n");
    out->printf("transfer cache, and central cache, by size class\n");
    out->printf("------------------------------------------------\n");
    uint64_t cumulative_bytes = 0;
    uint64_t cumulative_overhead = 0;
    for (uint32_t cl = 0; cl < Static::num_size_classes(); ++cl) {
      if (class_count[cl] > 0) {
        size_t cl_size = Static::sizemap()->ByteSizeForClass(cl);
        const uint64_t class_bytes = class_count[cl] * cl_size;
        cumulative_bytes += class_bytes;
        const uint64_t class_overhead =
            Static::central_cache()[cl].OverheadBytes();
        cumulative_overhead += class_overhead;
        out->printf("class %3d [ %8zu bytes ] : "
                "%8" PRIu64 " objs; %5.1f MiB; %5.1f cum MiB; "
                "%8.3f overhead MiB; %8.3f cum overhead MiB\n",
                cl, cl_size,
                class_count[cl],
                class_bytes / MiB,
                cumulative_bytes / MiB,
                class_overhead / MiB,
                cumulative_overhead / MiB);
      }
    }

    // append page heap info
    int nonempty_sizes = 0;
    for (int s = 0; s < kMaxPages; s++) {
      if (small.normal_length[s] + small.returned_length[s] > 0) {
        nonempty_sizes++;
      }
    }
    out->printf("------------------------------------------------\n");
    out->printf("PageHeap: %d sizes; %6.1f MiB free; %6.1f MiB unmapped\n",
                nonempty_sizes, stats.pageheap.free_bytes / MiB,
                stats.pageheap.unmapped_bytes / MiB);
    out->printf("------------------------------------------------\n");
    uint64_t total_normal = 0;
    uint64_t total_returned = 0;
    for (int s = 1; s <= kMaxPages; s++) {
      const int n_length = small.normal_length[s - 1];
      const int r_length = small.returned_length[s - 1];
      if (n_length + r_length > 0) {
        uint64_t n_pages = s * n_length;
        uint64_t r_pages = s * r_length;
        total_normal += n_pages;
        total_returned += r_pages;
        out->printf("%6u pages * %6u spans ~ %6.1f MiB; %6.1f MiB cum"
                    "; unmapped: %6.1f MiB; %6.1f MiB cum\n",
                    s,
                    (n_length + r_length),
                    PagesToMiB(n_pages + r_pages),
                    PagesToMiB(total_normal + total_returned),
                    PagesToMiB(r_pages),
                    PagesToMiB(total_returned));
      }
    }

    total_normal += large.normal_pages;
    total_returned += large.returned_pages;
    out->printf(">%-5u large * %6u spans ~ %6.1f MiB; %6.1f MiB cum"
                "; unmapped: %6.1f MiB; %6.1f MiB cum\n",
                static_cast(kMaxPages),
                static_cast(large.spans),
                PagesToMiB(large.normal_pages + large.returned_pages),
                PagesToMiB(total_normal + total_returned),
                PagesToMiB(large.returned_pages),
                PagesToMiB(total_returned));
  }
}

static void PrintStats(int level) {
  const int kBufferSize = 16 << 10;
  char* buffer = new char[kBufferSize];
  TCMalloc_Printer printer(buffer, kBufferSize);
  DumpStats(&printer, level);
  auto unused = write(STDERR_FILENO, buffer, strlen(buffer));
  (void)unused;
  delete[] buffer;
}

static void IterateOverRanges(void* arg, MallocExtension::RangeFunction func) {
  PageID page = 1;  // Some code may assume that page==0 is never used
  bool done = false;
  while (!done) {
    // Accumulate a small number of ranges in a local buffer
    static const int kNumRanges = 16;
    static base::MallocRange ranges[kNumRanges];
    int n = 0;
    {
      SpinLockHolder h(Static::pageheap_lock());
      while (n < kNumRanges) {
        if (!Static::pageheap()->GetNextRange(page, &ranges[n])) {
          done = true;
          break;
        } else {
          uintptr_t limit = ranges[n].address + ranges[n].length;
          page = (limit + kPageSize - 1) >> kPageShift;
          n++;
        }
      }
    }

    for (int i = 0; i < n; i++) {
      (*func)(arg, &ranges[i]);
    }
  }
}

namespace tcmalloc {

TestingPortal::~TestingPortal() = default;

class ATTRIBUTE_VISIBILITY_HIDDEN TestingPortalImpl : public TestingPortal {
public:
  ~TestingPortalImpl() override = default;

  bool HaveSystemRelease() override {
    static bool have = ([] () {
      size_t actual;
      auto ptr = TCMalloc_SystemAlloc(kPageSize, &actual, 0);
      return TCMalloc_SystemRelease(ptr, actual);
    })();
    return have;
  }
  bool IsDebuggingMalloc() override {
    return false;
  }
  size_t GetPageSize() override {
    return kPageSize;
  }
  size_t GetMinAlign() override {
    return kMinAlign;
  }
  size_t GetMaxSize() override {
    return kMaxSize;
  }
  int64_t& GetSampleParameter() override {
    return FLAGS_tcmalloc_sample_parameter;
  }
  double& GetReleaseRate() override {
    return FLAGS_tcmalloc_release_rate;
  }
  int32_t& GetMaxFreeQueueSize() override {
    abort();
  }

  bool HasEmergencyMalloc() override {
    return kUseEmergencyMalloc;
  }

  bool IsEmergencyPtr(void* ptr) override {
    return tcmalloc::IsEmergencyPtr(ptr);
  }

  void WithEmergencyMallocEnabled(FunctionRef body) override {
    auto body_adaptor = [body] (bool stacktrace_allowed) {
      CHECK(stacktrace_allowed);
      body();
    };
    FunctionRef ref{body_adaptor};
    ThreadCachePtr::WithStacktraceScope(ref.fn, ref.data);
  }

  uint32_t GetSizeClass(void* p) override {
    PageID pageid = reinterpret_cast(p) >> kPageShift;
    Span* span = Static::pageheap()->GetDescriptor(pageid);
    return span->sizeclass;
  }

  void* RunReallocWithCallback(
    void* old_ptr, size_t new_size,
    void (*invalid_free_fn)(void*),
    size_t (*invalid_get_size_fn)(const void*)) override;

  static TestingPortalImpl* Get() {
    static TestingPortalImpl* ptr = ([] () {
      static StaticStorage storage;
      return storage.Construct();
    }());
    return ptr;
  }
};

}  // namespace tcmalloc

using tcmalloc::TestingPortalImpl;

// TCMalloc's support for extra malloc interfaces
class TCMallocImplementation : public MallocExtension {
 private:
  // ReleaseToSystem() might release more than the requested bytes because
  // the page heap releases at the span granularity, and spans are of wildly
  // different sizes.  This member keeps track of the extra bytes bytes
  // released so that the app can periodically call ReleaseToSystem() to
  // release memory at a constant rate.
  // NOTE: Protected by Static::pageheap_lock().
  size_t extra_bytes_released_;

 public:
  TCMallocImplementation()
      : extra_bytes_released_(0) {
  }

  virtual void GetStats(char* buffer, int buffer_length) {
    ASSERT(buffer_length > 0);
    TCMalloc_Printer printer(buffer, buffer_length);

    // Print level one stats unless lots of space is available
    if (buffer_length < 10000) {
      DumpStats(&printer, 1);
    } else {
      DumpStats(&printer, 2);
    }
  }

  // We may print an extra, tcmalloc-specific warning message here.
  virtual void GetHeapSample(MallocExtensionWriter* writer) {
    if (FLAGS_tcmalloc_sample_parameter == 0) {
      const char* const kWarningMsg =
          "%warn\n"
          "%warn This heap profile does not have any data in it, because\n"
          "%warn the application was run with heap sampling turned off.\n"
          "%warn To get useful data from GetHeapSample(), you must\n"
          "%warn set the environment variable TCMALLOC_SAMPLE_PARAMETER to\n"
          "%warn a positive sampling period, such as 524288.\n"
          "%warn\n";
      writer->append(kWarningMsg, strlen(kWarningMsg));
    }
    MallocExtension::GetHeapSample(writer);
  }

  virtual void** ReadStackTraces(int* sample_period) {
    tcmalloc::StackTraceTable table;
    {
      SpinLockHolder h(Static::pageheap_lock());
      Span* sampled = Static::sampled_objects();
      for (Span* s = sampled->next; s != sampled; s = s->next) {
        table.AddTrace(*reinterpret_cast(s->objects));
      }
    }
    *sample_period = ThreadCachePtr::Grab()->GetSamplePeriod();
    return table.ReadStackTracesAndClear(); // grabs and releases pageheap_lock
  }

  virtual void** ReadHeapGrowthStackTraces() {
    // Note: growth stacks are append only, and updated atomically. So
    // we can just read them without any locks. And use arbitrarily long
    // (since they're never cleared/deleted).
    const StackTrace* head = Static::growth_stacks();
    return ProduceStackTracesDump(
      +[] (const void** current_head) {
        const StackTrace* current = static_cast(*current_head);
        *current_head = current->stack[tcmalloc::kMaxStackDepth-1];
        return current;
      }, head).release();
  }

  virtual size_t GetThreadCacheSize() {
    ThreadCache* tc = ThreadCachePtr::GetIfPresent();
    if (!tc)
      return 0;
    return tc->Size();
  }

  virtual void Ranges(void* arg, RangeFunction func) {
    IterateOverRanges(arg, func);
  }

  virtual bool GetNumericProperty(const char* name, size_t* value) {
    ASSERT(name != nullptr);

    if (strcmp(name, "generic.current_allocated_bytes") == 0) {
      TCMallocStats stats;
      ExtractStats(&stats, nullptr, nullptr, nullptr);
      *value = stats.pageheap.system_bytes
               - stats.thread_bytes
               - stats.central_bytes
               - stats.transfer_bytes
               - stats.pageheap.free_bytes
               - stats.pageheap.unmapped_bytes;
      return true;
    }

    if (strcmp(name, "generic.heap_size") == 0) {
      TCMallocStats stats;
      ExtractStats(&stats, nullptr, nullptr, nullptr);
      *value = stats.pageheap.system_bytes;
      return true;
    }

    if (strcmp(name, "generic.total_physical_bytes") == 0) {
      TCMallocStats stats;
      ExtractStats(&stats, nullptr, nullptr, nullptr);
      *value = stats.pageheap.system_bytes + stats.metadata_bytes -
               stats.pageheap.unmapped_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.slack_bytes") == 0) {
      // Kept for backwards compatibility.  Now defined externally as:
      //    pageheap_free_bytes + pageheap_unmapped_bytes.
      SpinLockHolder l(Static::pageheap_lock());
      PageHeap::Stats stats = Static::pageheap()->StatsLocked();
      *value = stats.free_bytes + stats.unmapped_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.central_cache_free_bytes") == 0) {
      TCMallocStats stats;
      ExtractStats(&stats, nullptr, nullptr, nullptr);
      *value = stats.central_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.transfer_cache_free_bytes") == 0) {
      TCMallocStats stats;
      ExtractStats(&stats, nullptr, nullptr, nullptr);
      *value = stats.transfer_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.thread_cache_free_bytes") == 0) {
      TCMallocStats stats;
      ExtractStats(&stats, nullptr, nullptr, nullptr);
      *value = stats.thread_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_free_bytes") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().free_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_unmapped_bytes") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().unmapped_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_committed_bytes") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().committed_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_scavenge_count") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().scavenge_count;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_commit_count") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().commit_count;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_total_commit_bytes") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().total_commit_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_decommit_count") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().decommit_count;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_total_decommit_bytes") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().total_decommit_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_reserve_count") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().reserve_count;
      return true;
    }

    if (strcmp(name, "tcmalloc.pageheap_total_reserve_bytes") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = Static::pageheap()->StatsLocked().total_reserve_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.max_total_thread_cache_bytes") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = ThreadCache::overall_thread_cache_size();
      return true;
    }

    if (strcmp(name, "tcmalloc.min_per_thread_cache_bytes") == 0) {
      *value = ThreadCache::min_per_thread_cache_size();
      return true;
    }

    if (strcmp(name, "tcmalloc.current_total_thread_cache_bytes") == 0) {
      TCMallocStats stats;
      ExtractStats(&stats, nullptr, nullptr, nullptr);
      *value = stats.thread_bytes;
      return true;
    }

    if (strcmp(name, "tcmalloc.aggressive_memory_decommit") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = size_t(Static::pageheap()->GetAggressiveDecommit());
      return true;
    }

    if (strcmp(name, "tcmalloc.heap_limit_mb") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      *value = FLAGS_tcmalloc_heap_limit_mb;
      return true;
    }

    if (strcmp(name, "tcmalloc.impl.thread_cache_count") == 0) {
      SpinLockHolder h(Static::pageheap_lock());
      *value = ThreadCache::thread_heap_count();
      return true;
    }

    if (strcmp(name, "tcmalloc.sample_parameter") == 0) {
      *value = FLAGS_tcmalloc_sample_parameter;
      return true;
    }

    if (TestingPortal** portal = TestingPortal::CheckGetPortal(name, value); portal) {
      *portal = TestingPortalImpl::Get();
      *value = 1;
      return true;
    }

    return false;
  }

  virtual bool SetNumericProperty(const char* name, size_t value) {
    ASSERT(name != nullptr);

    if (strcmp(name, "tcmalloc.max_total_thread_cache_bytes") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      ThreadCache::set_overall_thread_cache_size(value);
      return true;
    }

    if (strcmp(name, "tcmalloc.min_per_thread_cache_bytes") == 0) {
      ThreadCache::set_min_per_thread_cache_size(value);
      return true;
    }

    if (strcmp(name, "tcmalloc.aggressive_memory_decommit") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      Static::pageheap()->SetAggressiveDecommit(value != 0);
      return true;
    }

    if (strcmp(name, "tcmalloc.heap_limit_mb") == 0) {
      SpinLockHolder l(Static::pageheap_lock());
      FLAGS_tcmalloc_heap_limit_mb = value;
      return true;
    }

    if (strcmp(name, "tcmalloc.sample_parameter") == 0) {
      FLAGS_tcmalloc_sample_parameter = value;
      // By clearing current thread's cache we force next allocations
      // to read freshly updated sample parameter. This is only going
      // to affect current thread, but this is better than nothing.
      MallocExtension::instance()->MarkThreadIdle();
      return true;
    }

    return false;
  }

  // Note, in gperftools 2.5 we introduced this 'ligher-weight'
  // equivalent of MarkThreadIdle, but as of now mongo folk tells us
  // they don't use it anymore. And there was indeed possible issue
  // with this approach since it didn't 'return' thread's share of
  // total thread cache back to common pool. But that was almost
  // exactly the difference between regular mark idle and mark
  // "temporarily" idle. So we now go back to original mark idle, but
  // keep API for ABI and API compat sake.
  virtual void MarkThreadTemporarilyIdle() {
    MarkThreadIdle();
  }

  virtual void MarkThreadIdle() {
    ThreadCache* cache = ThreadCachePtr::ReleaseAndClear();
    if (cache) {
      // When our thread had cache, lets delete it
      ThreadCache::DeleteCache(cache);
    }
  }

  virtual void MarkThreadBusy();  // Implemented below

  virtual SysAllocator* GetSystemAllocator() {
    SpinLockHolder h(Static::pageheap_lock());
    return tcmalloc_sys_alloc;
  }

  virtual void SetSystemAllocator(SysAllocator* alloc) {
    SpinLockHolder h(Static::pageheap_lock());
    tcmalloc_sys_alloc = alloc;
  }

  virtual void ReleaseToSystem(size_t num_bytes) {
    SpinLockHolder h(Static::pageheap_lock());
    if (num_bytes <= extra_bytes_released_) {
      // We released too much on a prior call, so don't release any
      // more this time.
      extra_bytes_released_ = extra_bytes_released_ - num_bytes;
      return;
    }
    num_bytes = num_bytes - extra_bytes_released_;
    // num_bytes might be less than one page.  If we pass zero to
    // ReleaseAtLeastNPages, it won't do anything, so we release a whole
    // page now and let extra_bytes_released_ smooth it out over time.
    Length num_pages = std::max(num_bytes >> kPageShift, 1);
    size_t bytes_released = Static::pageheap()->ReleaseAtLeastNPages(
        num_pages) << kPageShift;
    if (bytes_released > num_bytes) {
      extra_bytes_released_ = bytes_released - num_bytes;
    } else {
      // The PageHeap wasn't able to release num_bytes.  Don't try to
      // compensate with a big release next time.  Specifically,
      // ReleaseFreeMemory() calls ReleaseToSystem(LONG_MAX).
      extra_bytes_released_ = 0;
    }
  }

  virtual void SetMemoryReleaseRate(double rate) {
    FLAGS_tcmalloc_release_rate = rate;
  }

  virtual double GetMemoryReleaseRate() {
    return FLAGS_tcmalloc_release_rate;
  }
  virtual size_t GetEstimatedAllocatedSize(size_t size);

  // This just calls GetSizeWithCallback, but because that's in an
  // unnamed namespace, we need to move the definition below it in the
  // file.
  virtual size_t GetAllocatedSize(const void* ptr);

  // This duplicates some of the logic in GetSizeWithCallback, but is
  // faster.  This is important on OS X, where this function is called
  // on every allocation operation.
  virtual Ownership GetOwnership(const void* ptr) {
    const PageID p = reinterpret_cast(ptr) >> kPageShift;
    // The rest of tcmalloc assumes that all allocated pointers use at
    // most kAddressBits bits.  If ptr doesn't, then it definitely
    // wasn't alloacted by tcmalloc.
    if ((p >> (kAddressBits - kPageShift)) > 0) {
      return kNotOwned;
    }
    uint32_t cl;
    if (Static::pageheap()->TryGetSizeClass(p, &cl)) {
      return kOwned;
    }
    const Span *span = Static::pageheap()->GetDescriptor(p);
    if (span) {
      return kOwned;
    }
    return tcmalloc::IsEmergencyPtr(ptr) ? kOwned : kNotOwned;
  }

  virtual void GetFreeListSizes(std::vector* v) {
    static const char kCentralCacheType[] = "tcmalloc.central";
    static const char kTransferCacheType[] = "tcmalloc.transfer";
    static const char kThreadCacheType[] = "tcmalloc.thread";
    static const char kPageHeapType[] = "tcmalloc.page";
    static const char kPageHeapUnmappedType[] = "tcmalloc.page_unmapped";
    static const char kLargeSpanType[] = "tcmalloc.large";
    static const char kLargeUnmappedSpanType[] = "tcmalloc.large_unmapped";

    v->clear();

    // central class information
    int64_t prev_class_size = 0;
    for (int cl = 1; cl < Static::num_size_classes(); ++cl) {
      size_t class_size = Static::sizemap()->ByteSizeForClass(cl);
      MallocExtension::FreeListInfo i;
      i.min_object_size = prev_class_size + 1;
      i.max_object_size = class_size;
      i.total_bytes_free =
          Static::central_cache()[cl].length() * class_size;
      i.type = kCentralCacheType;
      v->push_back(i);

      // transfer cache
      i.total_bytes_free =
          Static::central_cache()[cl].tc_length() * class_size;
      i.type = kTransferCacheType;
      v->push_back(i);

      prev_class_size = Static::sizemap()->ByteSizeForClass(cl);
    }

    // Add stats from per-thread heaps
    uint64_t class_count[kClassSizesMax];
    memset(class_count, 0, sizeof(class_count));
    {
      SpinLockHolder h(Static::pageheap_lock());
      uint64_t thread_bytes = 0;
      ThreadCache::GetThreadStats(&thread_bytes, class_count);
    }

    prev_class_size = 0;
    for (int cl = 1; cl < Static::num_size_classes(); ++cl) {
      MallocExtension::FreeListInfo i;
      i.min_object_size = prev_class_size + 1;
      i.max_object_size = Static::sizemap()->ByteSizeForClass(cl);
      i.total_bytes_free =
          class_count[cl] * Static::sizemap()->ByteSizeForClass(cl);
      i.type = kThreadCacheType;
      v->push_back(i);

      prev_class_size = Static::sizemap()->ByteSizeForClass(cl);
    }

    // append page heap info
    PageHeap::SmallSpanStats small;
    PageHeap::LargeSpanStats large;
    {
      SpinLockHolder h(Static::pageheap_lock());
      Static::pageheap()->GetSmallSpanStatsLocked(&small);
      Static::pageheap()->GetLargeSpanStatsLocked(&large);
    }

    // large spans: mapped
    MallocExtension::FreeListInfo span_info;
    span_info.type = kLargeSpanType;
    span_info.max_object_size = (std::numeric_limits::max)();
    span_info.min_object_size = kMaxPages << kPageShift;
    span_info.total_bytes_free = large.normal_pages << kPageShift;
    v->push_back(span_info);

    // large spans: unmapped
    span_info.type = kLargeUnmappedSpanType;
    span_info.total_bytes_free = large.returned_pages << kPageShift;
    v->push_back(span_info);

    // small spans
    for (int s = 1; s <= kMaxPages; s++) {
      MallocExtension::FreeListInfo i;
      i.max_object_size = (s << kPageShift);
      i.min_object_size = ((s - 1) << kPageShift);

      i.type = kPageHeapType;
      i.total_bytes_free = (s << kPageShift) * small.normal_length[s - 1];
      v->push_back(i);

      i.type = kPageHeapUnmappedType;
      i.total_bytes_free = (s << kPageShift) * small.returned_length[s - 1];
      v->push_back(i);
    }
  }
};

static ALWAYS_INLINE
size_t align_size_up(size_t size, size_t align) {
  ASSERT(align <= kPageSize);
  size_t new_size = (size + align - 1) & ~(align - 1);
  if (PREDICT_FALSE(new_size == 0)) {
    // Note, new_size == 0 catches both integer overflow and size
    // being 0.
    if (size == 0) {
      new_size = align;
    } else {
      new_size = size;
    }
  }
  return new_size;
}

// Puts in *cl size class that is suitable for allocation of size bytes with
// align alignment. Returns true if such size class exists and false otherwise.
static bool size_class_with_alignment(size_t size, size_t align, uint32_t* cl) {
  if (PREDICT_FALSE(align > kPageSize)) {
    return false;
  }
  size = align_size_up(size, align);
  if (PREDICT_FALSE(!Static::sizemap()->GetSizeClass(size, cl))) {
    return false;
  }
  ASSERT((Static::sizemap()->class_to_size(*cl) & (align - 1)) == 0);
  return true;
}

// nallocx slow path. Moved to a separate function because
// ThreadCache::InitModule is not inlined which would cause nallocx to
// become non-leaf function with stack frame and stack spills.
static ATTRIBUTE_NOINLINE size_t nallocx_slow(size_t size, int flags) {
  ThreadCache::EnsureMallocInitialized();

  size_t align = static_cast(1ull << (flags & 0x3f));
  uint32_t cl;
  bool ok = size_class_with_alignment(size, align, &cl);
  if (ok) {
    return Static::sizemap()->ByteSizeForClass(cl);
  } else {
    Length pages = tcmalloc::pages(size);
    pages = Static::pageheap()->RoundUpSize(pages);
    return pages << kPageShift;
  }
}

// The nallocx function allocates no memory, but it performs the same size
// computation as the malloc function, and returns the real size of the
// allocation that would result from the equivalent malloc function call.
// nallocx is a malloc extension originally implemented by jemalloc:
// http://www.unix.com/man-page/freebsd/3/nallocx/
extern "C" PERFTOOLS_DLL_DECL
size_t tc_nallocx(size_t size, int flags) {
  if (PREDICT_FALSE(flags != 0)) {
    return nallocx_slow(size, flags);
  }
  uint32_t cl;
  // size class 0 is only possible if malloc is not yet initialized
  if (Static::sizemap()->GetSizeClass(size, &cl) && cl != 0) {
    return Static::sizemap()->ByteSizeForClass(cl);
  } else {
    return nallocx_slow(size, 0);
  }
}

extern "C" PERFTOOLS_DLL_DECL
size_t nallocx(size_t size, int flags)
#ifdef TC_ALIAS
  TC_ALIAS(tc_nallocx);
#else
{
  return nallocx_slow(size, flags);
}
#endif


size_t TCMallocImplementation::GetEstimatedAllocatedSize(size_t size) {
  return tc_nallocx(size, 0);
}

// The constructor allocates an object to ensure that initialization
// runs before main(), and therefore we do not have a chance to become
// multi-threaded before initialization.  We also create the TSD key
// here.  Presumably by the time this constructor runs, runtime is in
// good enough shape to handle tcmalloc::CreateTlsKey().
//
// The destructor prints stats when the program exits.
static int tcmallocguard_refcount;
TCMallocGuard::TCMallocGuard() {
  if (tcmallocguard_refcount++ > 0) {
    return;
  }

#ifndef WIN32_OVERRIDE_ALLOCATORS
  ReplaceSystemAlloc();    // defined in libc_override_*.h
  (void)MallocExtension::instance(); // make sure malloc extension is constructed
  tc_free(tc_malloc(1));
#endif  // !WIN32_OVERRIDE_ALLOCATORS

  ThreadCachePtr::InitThreadCachePtrLate();
  tc_free(tc_malloc(1));
}

TCMallocGuard::~TCMallocGuard() {
  if (--tcmallocguard_refcount == 0) {
    const char* env = nullptr;
    if (!RunningOnValgrind()) {
      // Valgrind uses it's own malloc so we cannot do MALLOCSTATS
      env = getenv("MALLOCSTATS");
    }
    if (env != nullptr) {
      int level = atoi(env);
      if (level < 1) level = 1;
      PrintStats(level);
    }
  }
}

static TCMallocGuard module_enter_exit_hook;

#ifndef TCMALLOC_USING_DEBUGALLOCATION

static tcmalloc::StaticStorage malloc_impl_storage;

void SetupMallocExtension() {
  MallocExtension::Register(malloc_impl_storage.Construct());
}

#endif  // TCMALLOC_USING_DEBUGALLOCATION

//-------------------------------------------------------------------
// Helpers for the exported routines below
//-------------------------------------------------------------------

static ATTRIBUTE_UNUSED bool CheckCachedSizeClass(void *ptr) {
  PageID p = reinterpret_cast(ptr) >> kPageShift;
  uint32_t cached_value;
  if (!Static::pageheap()->TryGetSizeClass(p, &cached_value)) {
    return true;
  }
  return cached_value == Static::pageheap()->GetDescriptor(p)->sizeclass;
}

static ALWAYS_INLINE void* CheckedMallocResult(void *result) {
  ASSERT(result == nullptr || CheckCachedSizeClass(result));
  return result;
}

static ALWAYS_INLINE void* SpanToMallocResult(Span *span) {
  return
      CheckedMallocResult(reinterpret_cast(span->start << kPageShift));
}

static void* DoSampledAllocation(size_t size) {
#ifndef NO_TCMALLOC_SAMPLES
  // Grab the stack trace outside the heap lock
  StackTrace tmp;
  tmp.depth = tcmalloc::GrabBacktrace(tmp.stack, tcmalloc::kMaxStackDepth, 1);
  tmp.size = size;

  // Allocate span
  auto pages = tcmalloc::pages(size == 0 ? 1 : size);
  Span *span = Static::pageheap()->New(pages);
  if (PREDICT_FALSE(span == nullptr)) {
    return nullptr;
  }

  SpinLockHolder h(Static::pageheap_lock());

  // Allocate stack trace
  StackTrace *stack = Static::stacktrace_allocator()->New();
  if (PREDICT_TRUE(stack != nullptr)) {
    *stack = tmp;
    span->sample = 1;
    span->objects = stack;
    tcmalloc::DLL_Prepend(Static::sampled_objects(), span);
  }

  return SpanToMallocResult(span);
#else
  abort();
#endif
}

namespace {

typedef void* (*malloc_fn)(void *arg);

void* handle_oom(malloc_fn retry_fn,
                 void* retry_arg,
                 bool from_operator,
                 bool nothrow) {
  // we hit out of memory condition, usually if it happens we've
  // called sbrk or mmap and failed, and thus errno is set. But there
  // is support for setting up custom system allocator or setting up
  // page heap size limit, in which cases errno may remain
  // untouched.
  //
  // So we set errno here. C++ operator new doesn't require ENOMEM to
  // be set, but doesn't forbid it too (and often C++ oom does happen
  // with ENOMEM set).
  errno = ENOMEM;
  if (!from_operator && !tc_new_mode) {
    // we're out of memory in C library function (malloc etc) and no
    // "new mode" forced on us. Just return nullptr
    return nullptr;
  }

  // we're OOM in operator new or "new mode" is set. We might have to
  // call new_handler and maybe retry allocation.

  for (;;) {
    // Get the current new handler.  NB: this function is not
    // thread-safe.  We make a feeble stab at making it so here, but
    // this lock only protects against tcmalloc interfering with
    // itself, not with other libraries calling set_new_handler.
    std::new_handler nh = std::get_new_handler();
#if __cpp_exceptions
    // If no new_handler is established, the allocation failed.
    if (!nh) {
      if (nothrow) {
        return nullptr;
      }
      throw std::bad_alloc();
    }
    // Otherwise, try the new_handler.  If it returns, retry the
    // allocation.  If it throws std::bad_alloc, fail the allocation.
    // if it throws something else, don't interfere.
    try {
      (*nh)();
    } catch (const std::bad_alloc&) {
      if (!nothrow) throw;
      return nullptr;
    }
#else
    if (!nh) {
      if (nothrow) {
        return nullptr;
      }
      Log(kCrash, __FILE__, __LINE__, "C++ OOM in -fno-exceptions case");
    }
    // Since exceptions are disabled, we don't really know if new_handler
    // failed.  Assume it will abort if it fails.
    (*nh)();
#endif  // !__cpp_exceptions

    // we get here if new_handler returns successfully. So we retry
    // allocation.
    void* rv = retry_fn(retry_arg);
    if (rv != nullptr) {
      return rv;
    }

    // if allocation failed again we go to next loop iteration
  }
}

static void ReportLargeAlloc(Length num_pages, void* result) {
  StackTrace stack;
  stack.depth = tcmalloc::GrabBacktrace(stack.stack, tcmalloc::kMaxStackDepth, 1);

  static const int N = 1000;
  char buffer[N];
  TCMalloc_Printer printer(buffer, N);
  printer.printf("tcmalloc: large alloc %" PRIu64 " bytes == %p @ ",
                 static_cast(num_pages) << kPageShift,
                 result);
  for (int i = 0; i < stack.depth; i++) {
    printer.printf(" %p", stack.stack[i]);
  }
  printer.printf("\n");
  auto unused = write(STDERR_FILENO, buffer, strlen(buffer));
  (void)unused;
}

static bool should_report_large(Length num_pages) {
#ifdef ENABLE_LARGE_ALLOC_REPORT
// For windows, the printf we use to report large allocs is
// potentially dangerous: it could cause a malloc that would cause an
// infinite loop.  So by default we set the threshold to a huge number
// on windows, so this bad situation will never trigger.  You can
// always set TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD manually if you
// want this functionality.
#ifdef _WIN32
  constexpr auto kDefaultLargeAllocReportThreshold = int64_t{1} << 62;
#else
  constexpr auto kDefaultLargeAllocReportThreshold = int64_t{1} << 30;
#endif

  // Note, our 'reporting threshold setting' is 64-bit, but we can
  // only afford size_t threshold variable. I.e. some 32-bit machines
  // don't support 64-bit atomics. So some care is taken to cast etc.
  static std::atomic large_alloc_threshold;
  size_t threshold = large_alloc_threshold.load(std::memory_order_relaxed);

  if (threshold == 0) {
    int64_t value = tcmalloc::commandlineflags::StringToLongLong(
      TCMallocGetenvSafe("TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD"),
      kDefaultLargeAllocReportThreshold);
    if (value < 0) {
      // Negative limit means disable reporting
      value = std::numeric_limits::max();
    }
    value = std::max(kPageSize, value);

    if (sizeof(size_t) < sizeof(int64_t)) {
      // On 32-bit machines size_t is narrower than int64_t. So lets
      // make limits larger than size_t's max (i.e. overflowing 32-bit
      // unsigned int) to be infinity.
      value = std::min(value, std::numeric_limits::max());
    }

    threshold = static_cast(value);
    large_alloc_threshold.store(threshold); // harmless to race
  }

  do {
    if (PREDICT_TRUE(num_pages < (threshold >> kPageShift))) {
      return false;
    }

    // Increase the threshold by 1/8 every time we generate a report.
    size_t new_threshold = threshold + threshold / 8;
    if (new_threshold < threshold) {
      new_threshold = std::numeric_limits::max();
    }

    // Also make new threshold at least as big as the allocation that
    // triggered the reporting.
    new_threshold = std::max(new_threshold,
                                     num_pages << kPageShift);

    if (large_alloc_threshold.compare_exchange_strong(
          threshold, new_threshold,
          std::memory_order_relaxed, std::memory_order_relaxed)) {
      return true;
    }
  } while (true);

#endif
  return false;
}

// Helper for do_malloc().
static void* do_malloc_pages(ThreadCache* heap, size_t size) {
  void* result;

  Length num_pages = tcmalloc::pages(size);

  // NOTE: we're passing original size here as opposed to rounded-up
  // size as we do in do_malloc_small. The difference is small here
  // (at most 4k out of at least 256k). And not rounding up saves us
  // from possibility of overflow, which rounding up could produce.
  //
  // See https://github.com/gperftools/gperftools/issues/723
  if (heap->SampleAllocation(size)) {
    result = DoSampledAllocation(size);
  } else {
    Span* span = Static::pageheap()->New(num_pages);
    result = (PREDICT_FALSE(span == nullptr) ? nullptr : SpanToMallocResult(span));
  }

  if (should_report_large(num_pages)) {
    ReportLargeAlloc(num_pages, result);
  }
  return result;
}

static void *nop_oom_handler(size_t size) {
  return nullptr;
}

ALWAYS_INLINE void* do_malloc(size_t size) {
  // note: it will force initialization of malloc if necessary
  ThreadCachePtr cache_ptr = ThreadCachePtr::Grab();
  if (PREDICT_FALSE(cache_ptr.IsEmergencyMallocEnabled())) {
    return tcmalloc::EmergencyMalloc(size);
  }

  uint32_t cl;

  ASSERT(Static::IsInited());
  ASSERT(cache_ptr.get() != nullptr);

  if (PREDICT_FALSE(!Static::sizemap()->GetSizeClass(size, &cl))) {
    return do_malloc_pages(cache_ptr.get(), size);
  }

  size_t allocated_size = Static::sizemap()->class_to_size(cl);
  if (PREDICT_FALSE(cache_ptr->SampleAllocation(allocated_size))) {
    return DoSampledAllocation(size);
  }

  // The common case, and also the simplest.  This just pops the
  // size-appropriate freelist, after replenishing it if it's empty.
  return CheckedMallocResult(
    cache_ptr->Allocate(allocated_size, cl, nop_oom_handler));
}

static void *retry_malloc(void* size) {
  return do_malloc(reinterpret_cast(size));
}

ALWAYS_INLINE void* do_malloc_or_cpp_alloc(size_t size) {
  void *rv = do_malloc(size);
  if (PREDICT_TRUE(rv != nullptr)) {
    return rv;
  }
  return handle_oom(retry_malloc, reinterpret_cast(size),
                    false, true);
}

ALWAYS_INLINE void* do_calloc(size_t n, size_t elem_size) {
  // Overflow check
  const size_t size = n * elem_size;
  if (elem_size != 0 && size / elem_size != n) return nullptr;

  void* result = do_malloc_or_cpp_alloc(size);
  if (result != nullptr) {
    size_t total_size = size;
    if (!tcmalloc::IsEmergencyPtr(result)) {
      // On windows we support recalloc (which was apparently
      // originally introduced in Irix). In order for recalloc to work
      // we need to zero-out not just the size we were asked for, but
      // entire usable size. See also
      // https://github.com/gperftools/gperftools/pull/994.
      //
      // But we can do it only when not dealing with emergency
      // malloc-ed memory.
      total_size = tc_nallocx(size, 0);
    }
    memset(result, 0, total_size);
  }
  return result;
}

// If ptr is nullptr, do nothing.  Otherwise invoke the given function.
inline void free_null_or_invalid(void* ptr, void (*invalid_free_fn)(void*)) {
  if (ptr != nullptr) {
    (*invalid_free_fn)(ptr);
  }
}

static ATTRIBUTE_NOINLINE void do_free_pages(Span* span, void* ptr) {
  // Check to see if the object is in use.
  CHECK_CONDITION_PRINT(span->location == Span::IN_USE,
                        "Object was not in-use");
  CHECK_CONDITION_PRINT(
      span->start << kPageShift == reinterpret_cast(ptr),
      "Pointer is not pointing to the start of a span");

  Static::pageheap()->PrepareAndDelete(span, [&] () {
    if (span->sample) {
      StackTrace* st = reinterpret_cast(span->objects);
      tcmalloc::DLL_Remove(span);
      Static::stacktrace_allocator()->Delete(st);
      span->objects = nullptr;
    }
  });
}

#ifndef NDEBUG
// note, with sized deletions we have no means to support win32
// behavior where we detect "not ours" points and delegate them native
// memory management. This is because nature of sized deletes
// bypassing addr -> size class checks. So in this validation code we
// also assume that sized delete is always used with "our" pointers.
bool ValidateSizeHint(void* ptr, size_t size_hint) {
  const PageID p = reinterpret_cast(ptr) >> kPageShift;
  Span* span  = Static::pageheap()->GetDescriptor(p);
  uint32_t cl = 0;
  Static::sizemap()->GetSizeClass(size_hint, &cl);
  return (span->sizeclass == cl);
}
#endif

// Helper for the object deletion (free, delete, etc.).  Inputs:
//   ptr is object to be freed
//   invalid_free_fn is a function that gets invoked on certain "bad frees"
//
// We can usually detect the case where ptr is not pointing to a page that
// tcmalloc is using, and in those cases we invoke invalid_free_fn.
ALWAYS_INLINE
void do_free_with_callback(void* ptr,
                           void (*invalid_free_fn)(void*),
                           bool use_hint, size_t size_hint) {
  ThreadCache* heap = ThreadCachePtr::GetIfPresent();

  const PageID p = reinterpret_cast(ptr) >> kPageShift;
  uint32_t cl;

  ASSERT(!use_hint || ValidateSizeHint(ptr, size_hint));

  if (!use_hint || PREDICT_FALSE(!Static::sizemap()->GetSizeClass(size_hint, &cl))) {
    // if we're in sized delete, but size is too large, no need to
    // probe size cache
    bool cache_hit = !use_hint && Static::pageheap()->TryGetSizeClass(p, &cl);
    if (PREDICT_FALSE(!cache_hit)) {
      Span* span  = Static::pageheap()->GetDescriptor(p);
      if (PREDICT_FALSE(!span)) {
        // span can be nullptr because the pointer passed in is nullptr or invalid
        // (not something returned by malloc or friends), or because the
        // pointer was allocated with some other allocator besides
        // tcmalloc.  The latter can happen if tcmalloc is linked in via
        // a dynamic library, but is not listed last on the link line.
        // In that case, libraries after it on the link line will
        // allocate with libc malloc, but free with tcmalloc's free.
        free_null_or_invalid(ptr, invalid_free_fn);
        return;
      }
      cl = span->sizeclass;
      if (PREDICT_FALSE(cl == 0)) {
        ASSERT(reinterpret_cast(ptr) % kPageSize == 0);
        ASSERT(span != nullptr && span->start == p);
        do_free_pages(span, ptr);
        return;
      }
      if (!use_hint) {
        Static::pageheap()->SetCachedSizeClass(p, cl);
      }
    }
  }

  if (PREDICT_TRUE(heap != nullptr)) {
    ASSERT(Static::IsInited());
    // If we've hit initialized thread cache, so we're done.
    heap->Deallocate(ptr, cl);
    return;
  }

  if (PREDICT_FALSE(!Static::IsInited())) {
    // if free was called very early we've could have missed the case
    // of invalid or nullptr free. I.e. because probing size classes
    // cache could return bogus result (cl = 0 as of this
    // writing). But since there is no way we could be dealing with
    // ptr we've allocated, since successfull malloc implies IsInited,
    // we can just call "invalid free" handling code.
    free_null_or_invalid(ptr, invalid_free_fn);
    return;
  }

  // Otherwise, delete directly into central cache
  tcmalloc::SLL_SetNext(ptr, nullptr);
  Static::central_cache()[cl].InsertRange(ptr, ptr, 1);
}

// The default "do_free" that uses the default callback.
ALWAYS_INLINE void do_free(void* ptr) {
  return do_free_with_callback(ptr, &InvalidFree, false, 0);
}

// NOTE: some logic here is duplicated in GetOwnership (above), for
// speed.  If you change this function, look at that one too.
inline size_t GetSizeWithCallback(const void* ptr,
                                  size_t (*invalid_getsize_fn)(const void*)) {
  if (ptr == nullptr)
    return 0;
  const PageID p = reinterpret_cast(ptr) >> kPageShift;
  uint32_t cl;
  if (Static::pageheap()->TryGetSizeClass(p, &cl)) {
    return Static::sizemap()->ByteSizeForClass(cl);
  }

  const Span *span = Static::pageheap()->GetDescriptor(p);
  if (PREDICT_FALSE(span == nullptr)) {  // means we do not own this memory
    return (*invalid_getsize_fn)(ptr);
  }

  if (span->sizeclass != 0) {
    return Static::sizemap()->ByteSizeForClass(span->sizeclass);
  }

  if (span->sample) {
    size_t orig_size = reinterpret_cast(span->objects)->size;
    return tc_nallocx(orig_size, 0);
  }

  return span->length << kPageShift;
}

// This lets you call back to a given function pointer if ptr is invalid.
// It is used primarily by windows code which wants a specialized callback.
ALWAYS_INLINE void* do_realloc_with_callback(
    void* old_ptr, size_t new_size,
    void (*invalid_free_fn)(void*),
    size_t (*invalid_get_size_fn)(const void*)) {

  size_t currently_usable = GetSizeWithCallback(
    old_ptr,
    +[] (const void* invalid_ptr) -> size_t {
      // If we're passed "invalid" object, have free step handle
      // either falling back to "pre-patch" msvc runtime, or reporting
      // invalid free. Returning 0 makes us bypass "keep in place"
      // option.
      return 0;
    });

  if (tc_nallocx(new_size, 0) == currently_usable) {
    // stay in place. Communicate new logical size to the hooks.
    //
    // Note: we're skipping sampling updates because we consider this
    // "allocation" 0-cost.
    tcmalloc::InvokeDeleteHook(old_ptr);
    tcmalloc::InvokeNewHook(old_ptr, new_size);
    return old_ptr;
  }

  void* new_ptr = do_malloc_or_cpp_alloc(new_size);
  if (new_ptr == nullptr) {
    // NOTE: Setting ENOMEM or any other kind of OOM handling has been
    // done in the do_malloc_or_cpp_alloc thingy.
    return nullptr;
  }

  if (currently_usable == 0) {
    // We had the "not our chunk of memory" case when fetching
    // currently_usable size. So lets get real old size so that memcpy
    // below is handled correctly.
    currently_usable = invalid_get_size_fn(old_ptr);
  }

  tcmalloc::InvokeNewHook(new_ptr, new_size);
  memcpy(new_ptr, old_ptr, std::min(currently_usable, new_size));
  tcmalloc::InvokeDeleteHook(old_ptr);

  // We could use a variant of do_free() that leverages the fact that
  // we already know the sizeclass of old_ptr.  The benefit would be
  // small, so don't bother.
  do_free_with_callback(old_ptr, invalid_free_fn, false, 0);
  return new_ptr;
}

static ALWAYS_INLINE
void* do_memalign_pages(size_t align, size_t size) {
  ASSERT((align & (align - 1)) == 0);
  ASSERT(align > kPageSize);
  if (size + align < size) return nullptr;         // Overflow

  if (PREDICT_FALSE(Static::pageheap() == nullptr)) ThreadCache::InitModule();

  // Allocate at least one byte to avoid boundary conditions below
  if (size == 0) size = 1;

  // We will allocate directly from the page heap
  Span* span = Static::pageheap()->NewAligned(tcmalloc::pages(size),
                                              tcmalloc::pages(align));
  if (span == nullptr) {
    // errno was set inside page heap as necessary.
    return nullptr;
  }

  return SpanToMallocResult(span);
}

// Helpers for use by exported routines below:

inline void do_malloc_stats() {
  PrintStats(1);
}

inline int do_mallopt(int cmd, int value) {
  return 1;     // Indicates error
}

#if GPERFTOOLS_HAS_MALLINFO2 || GPERFTOOLS_HAS_MALLINFO
template 
inline Mallinfo do_mallinfo() {
  TCMallocStats stats;
  ExtractStats(&stats, nullptr, nullptr, nullptr);

  // Just some of the fields are filled in.
  Mallinfo info;
  memset(&info, 0, sizeof(info));

  // Note, struct mallinfo contains "int" fields, so some of the size
  // values will be truncated. But thankfully we also have
  // mallinfo2. We're able to produce code for both of those variants.
  using inttp = decltype(info.arena); // int or size_t in practice

  info.arena     = static_cast(stats.pageheap.system_bytes);
  info.fsmblks   = static_cast(stats.thread_bytes
                                      + stats.central_bytes
                                      + stats.transfer_bytes);
  info.fordblks  = static_cast(stats.pageheap.free_bytes +
                                      stats.pageheap.unmapped_bytes);
  info.uordblks  = static_cast(stats.pageheap.system_bytes
                                      - stats.thread_bytes
                                      - stats.central_bytes
                                      - stats.transfer_bytes
                                      - stats.pageheap.free_bytes
                                      - stats.pageheap.unmapped_bytes);

  return info;
}
#endif  // GPERFTOOLS_HAS_MALLINFO{,2}

}  // end unnamed namespace

// As promised, the definition of this function, declared above.
size_t TCMallocImplementation::GetAllocatedSize(const void* ptr) {
  if (ptr == nullptr)
    return 0;
  ASSERT(TCMallocImplementation::GetOwnership(ptr)
         != TCMallocImplementation::kNotOwned);
  return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize);
}

void TCMallocImplementation::MarkThreadBusy() {
  // Allocate to force the creation of a thread cache, but avoid
  // invoking any hooks.
  do_free(do_malloc(0));
}

//-------------------------------------------------------------------
// Exported routines
//-------------------------------------------------------------------

extern "C" PERFTOOLS_DLL_DECL const char* tc_version(
    int* major, int* minor, const char** patch) PERFTOOLS_NOTHROW {
  if (major) *major = TC_VERSION_MAJOR;
  if (minor) *minor = TC_VERSION_MINOR;
  if (patch) *patch = TC_VERSION_PATCH;
  return TC_VERSION_STRING;
}

// This function behaves similarly to MSVC's _set_new_mode.
// If flag is 0 (default), calls to malloc will behave normally.
// If flag is 1, calls to malloc will behave like calls to new,
// and the std_new_handler will be invoked on failure.
// Returns the previous mode.
extern "C" PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) PERFTOOLS_NOTHROW {
  int old_mode = tc_new_mode;
  tc_new_mode = flag;
  return old_mode;
}

extern "C" PERFTOOLS_DLL_DECL int tc_query_new_mode() PERFTOOLS_NOTHROW {
  return tc_new_mode;
}

namespace tcmalloc {
void* TestingPortalImpl::RunReallocWithCallback(
    void* old_ptr, size_t new_size,
    void (*invalid_free_fn)(void*),
    size_t (*invalid_get_size_fn)(const void*)) {
  return do_realloc_with_callback(old_ptr, new_size, invalid_free_fn, invalid_get_size_fn);
}
}


#ifndef TCMALLOC_USING_DEBUGALLOCATION  // debugallocation.cc defines its own

// CAVEAT: The code structure below ensures that MallocHook methods are always
//         called from the stack frame of the invoked allocation function.
//         heap-checker.cc depends on this to start a stack trace from
//         the call to the (de)allocation function.

namespace tcmalloc {


static ATTRIBUTE_NOINLINE
void invoke_hooks_and_free(void *ptr) {
  tcmalloc::InvokeDeleteHook(ptr);
  do_free(ptr);
}

ATTRIBUTE_NOINLINE
void* cpp_throw_oom(size_t size) {
  return handle_oom(retry_malloc, reinterpret_cast(size),
                    true, false);
}

ATTRIBUTE_NOINLINE
void* cpp_nothrow_oom(size_t size) {
  return handle_oom(retry_malloc, reinterpret_cast(size),
                    true, true);
}

ATTRIBUTE_NOINLINE
void* malloc_oom(size_t size) {
  return handle_oom(retry_malloc, reinterpret_cast(size),
                    false, true);
}

// tcmalloc::allocate_full_XXX is called by fast-path malloc when some
// complex handling is needed (such as fetching object from central
// freelist or malloc sampling). It contains all 'operator new' logic,
// as opposed to malloc_fast_path which only deals with important
// subset of cases.
//
// Note that this is under tcmalloc namespace so that pprof
// can automatically filter it out of growthz/heapz profiles.
//
// We have slightly fancy setup because we need to call hooks from
// function in 'google_malloc' section and we cannot place template
// into this section. Thus 3 separate functions 'built' by macros.
//
// Also note that we're carefully orchestrating for
// MallocHook::GetCallerStackTrace to work even if compiler isn't
// optimizing tail calls (e.g. -O0 is given). We still require
// ALWAYS_INLINE to work for that case, but it was seen to
// work for -O0 -fno-inline across both GCC and clang. I.e. in this
// case we'll get stack frame for tc_new, followed by stack frame for
// allocate_full_cpp_throw_oom, followed by hooks machinery and user
// code's stack frames. So GetCallerStackTrace will find 2
// subsequent stack frames in google_malloc section and correctly
// 'cut' stack trace just before tc_new.
template 
ALWAYS_INLINE
static void* do_allocate_full(size_t size) {
  void* p = do_malloc(size);
  if (PREDICT_FALSE(p == nullptr)) {
    p = OOMHandler(size);
  }
  tcmalloc::InvokeNewHook(p, size);
  return CheckedMallocResult(p);
}

#define AF(oom) \
  ATTRIBUTE_NOINLINE   \
  void* allocate_full_##oom(size_t size) {   \
    return do_allocate_full(size);     \
  }

AF(cpp_throw_oom)
AF(cpp_nothrow_oom)
AF(malloc_oom)

#undef AF

template 
static ALWAYS_INLINE void* dispatch_allocate_full(size_t size) {
  if (OOMHandler == cpp_throw_oom) {
    return allocate_full_cpp_throw_oom(size);
  }
  if (OOMHandler == cpp_nothrow_oom) {
    return allocate_full_cpp_nothrow_oom(size);
  }
  ASSERT(OOMHandler == malloc_oom);
  return allocate_full_malloc_oom(size);
}

struct retry_memalign_data {
  size_t align;
  size_t size;
};

static void *retry_do_memalign(void *arg) {
  retry_memalign_data *data = static_cast(arg);
  return do_memalign_pages(data->align, data->size);
}

static ATTRIBUTE_NOINLINE
void* memalign_pages(size_t align, size_t size,
                     bool from_operator, bool nothrow) {
  void *rv = do_memalign_pages(align, size);
  if (PREDICT_FALSE(rv == nullptr)) {
    retry_memalign_data data;
    data.align = align;
    data.size = size;
    rv = handle_oom(retry_do_memalign, &data,
                    from_operator, nothrow);
  }
  tcmalloc::InvokeNewHook(rv, size);
  return CheckedMallocResult(rv);
}

} // namespace tcmalloc

// This is quick, fast-path-only implementation of malloc/new. It is
// designed to only have support for fast-path. It checks if more
// complex handling is needed (such as a pageheap allocation or
// sampling) and only performs allocation if none of those uncommon
// conditions hold. When we have one of those odd cases it simply
// tail-calls to one of tcmalloc::allocate_full_XXX defined above.
//
// Such approach was found to be quite effective. Generated code for
// tc_{new,malloc} either succeeds quickly or tail-calls to
// allocate_full. Terseness of the source and lack of
// non-tail calls enables compiler to produce better code. Also
// produced code is short enough to enable effort-less human
// comprehension. Which itself led to elimination of various checks
// that were not necessary for fast-path.
template 
ALWAYS_INLINE
static void * malloc_fast_path(size_t size) {
  if (PREDICT_FALSE(!base::internal::new_hooks_.empty())) {
    return tcmalloc::dispatch_allocate_full(size);
  }

  ThreadCache *cache = ThreadCachePtr::GetIfPresent();

  if (PREDICT_FALSE(cache == nullptr)) {
    return tcmalloc::dispatch_allocate_full(size);
  }

  uint32_t cl;
  if (PREDICT_FALSE(!Static::sizemap()->GetSizeClass(size, &cl))) {
    return tcmalloc::dispatch_allocate_full(size);
  }

  size_t allocated_size = Static::sizemap()->ByteSizeForClass(cl);

  if (PREDICT_FALSE(!cache->TryRecordAllocationFast(allocated_size))) {
    return tcmalloc::dispatch_allocate_full(size);
  }

  return CheckedMallocResult(cache->Allocate(allocated_size, cl, OOMHandler));
}

template 
ALWAYS_INLINE
static void* memalign_fast_path(size_t align, size_t size) {
  if (PREDICT_FALSE(align > kPageSize)) {
    if (OOMHandler == tcmalloc::cpp_throw_oom) {
      return tcmalloc::memalign_pages(align, size, true, false);
    } else if (OOMHandler == tcmalloc::cpp_nothrow_oom) {
      return tcmalloc::memalign_pages(align, size, true, true);
    } else {
      ASSERT(OOMHandler == tcmalloc::malloc_oom);
      return tcmalloc::memalign_pages(align, size, false, true);
    }
  }

  // Everything with alignment <= kPageSize we can easily delegate to
  // regular malloc

  return malloc_fast_path(align_size_up(size, align));
}

extern "C" PERFTOOLS_DLL_DECL CACHELINE_ALIGNED_FN
void* tc_malloc(size_t size) PERFTOOLS_NOTHROW {
  return malloc_fast_path(size);
}

static ALWAYS_INLINE
void free_fast_path(void *ptr) {
  if (PREDICT_FALSE(!base::internal::delete_hooks_.empty())) {
    tcmalloc::invoke_hooks_and_free(ptr);
    return;
  }
  do_free(ptr);
}

extern "C" PERFTOOLS_DLL_DECL CACHELINE_ALIGNED_FN
void tc_free(void* ptr) PERFTOOLS_NOTHROW {
  free_fast_path(ptr);
}

extern "C" PERFTOOLS_DLL_DECL CACHELINE_ALIGNED_FN
void tc_free_sized(void *ptr, size_t size) PERFTOOLS_NOTHROW {
  if (PREDICT_FALSE(!base::internal::delete_hooks_.empty())) {
    tcmalloc::invoke_hooks_and_free(ptr);
    return;
  }
#ifndef NO_TCMALLOC_SAMPLES
  // if ptr is kPageSize-aligned, then it could be sampled allocation,
  // thus we don't trust hint and just do plain free. It also handles
  // nullptr for us.
  if (PREDICT_FALSE((reinterpret_cast(ptr) & (kPageSize-1)) == 0)) {
    tc_free(ptr);
    return;
  }
#else
  if (!ptr) {
    return;
  }
#endif
  do_free_with_callback(ptr, &InvalidFree, true, size);
}

#ifdef TC_ALIAS

extern "C" PERFTOOLS_DLL_DECL void tc_delete_sized(void *p, size_t size) PERFTOOLS_NOTHROW
  TC_ALIAS(tc_free_sized);
extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_sized(void *p, size_t size) PERFTOOLS_NOTHROW
  TC_ALIAS(tc_free_sized);

#else

extern "C" PERFTOOLS_DLL_DECL void tc_delete_sized(void *p, size_t size) PERFTOOLS_NOTHROW {
  tc_free_sized(p, size);
}
extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_sized(void *p, size_t size) PERFTOOLS_NOTHROW {
  tc_free_sized(p, size);
}

#endif

extern "C" PERFTOOLS_DLL_DECL void* tc_calloc(size_t n,
                                              size_t elem_size) PERFTOOLS_NOTHROW {
  void* result = do_calloc(n, elem_size);
  tcmalloc::InvokeNewHook(result, n * elem_size);
  return result;
}

extern "C" PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_free);
#else
{
  free_fast_path(ptr);
}
#endif

extern "C" PERFTOOLS_DLL_DECL void* tc_realloc(void* old_ptr,
                                               size_t new_size) PERFTOOLS_NOTHROW {
  if (old_ptr == nullptr) {
    void* result = do_malloc_or_cpp_alloc(new_size);
    tcmalloc::InvokeNewHook(result, new_size);
    return result;
  }
  if (new_size == 0) {
    tcmalloc::InvokeDeleteHook(old_ptr);
    do_free(old_ptr);
    return nullptr;
  }
  if (PREDICT_FALSE(tcmalloc::IsEmergencyPtr(old_ptr))) {
    return tcmalloc::EmergencyRealloc(old_ptr, new_size);
  }

  auto invalid_get_size = +[] (const void* old_ptr) -> size_t {
    Log(kCrash, __FILE__, __LINE__,
        "Attempt to realloc invalid pointer", old_ptr);
    return 0;
  };
  return do_realloc_with_callback(old_ptr, new_size,
                                  &InvalidFree, invalid_get_size);
}

extern "C" PERFTOOLS_DLL_DECL CACHELINE_ALIGNED_FN
void* tc_new(size_t size) {
  return malloc_fast_path(size);
}

extern "C" PERFTOOLS_DLL_DECL CACHELINE_ALIGNED_FN
void* tc_new_nothrow(size_t size, const std::nothrow_t&) PERFTOOLS_NOTHROW {
  return malloc_fast_path(size);
}

extern "C" PERFTOOLS_DLL_DECL void tc_delete(void* p) PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_free);
#else
{
  free_fast_path(p);
}
#endif

// Standard C++ library implementations define and use this
// (via ::operator delete(ptr, nothrow)).
// But it's really the same as normal delete, so we just do the same thing.
extern "C" PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) PERFTOOLS_NOTHROW
{
  if (PREDICT_FALSE(!base::internal::delete_hooks_.empty())) {
    tcmalloc::invoke_hooks_and_free(p);
    return;
  }
  do_free(p);
}

extern "C" PERFTOOLS_DLL_DECL void* tc_newarray(size_t size)
#ifdef TC_ALIAS
TC_ALIAS(tc_new);
#else
{
  return malloc_fast_path(size);
}
#endif

extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&)
    PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_new_nothrow);
#else
{
  return malloc_fast_path(size);
}
#endif

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray(void* p) PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_free);
#else
{
  free_fast_path(p);
}
#endif

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_delete_nothrow);
#else
{
  free_fast_path(p);
}
#endif

extern "C" PERFTOOLS_DLL_DECL CACHELINE_ALIGNED_FN
void* tc_memalign(size_t align, size_t size) PERFTOOLS_NOTHROW {
  return memalign_fast_path(align, size);
}

extern "C" PERFTOOLS_DLL_DECL int tc_posix_memalign(
    void** result_ptr, size_t align, size_t size) PERFTOOLS_NOTHROW {
  if (((align % sizeof(void*)) != 0) ||
      ((align & (align - 1)) != 0) ||
      (align == 0)) {
    return EINVAL;
  }

  void* result = tc_memalign(align, size);
  if (PREDICT_FALSE(result == nullptr)) {
    return ENOMEM;
  } else {
    *result_ptr = result;
    return 0;
  }
}

extern "C" PERFTOOLS_DLL_DECL void* tc_new_aligned(size_t size, std::align_val_t align) {
  return memalign_fast_path(static_cast(align), size);
}

extern "C" PERFTOOLS_DLL_DECL void* tc_new_aligned_nothrow(size_t size, std::align_val_t align, const std::nothrow_t&) PERFTOOLS_NOTHROW {
  return memalign_fast_path(static_cast(align), size);
}

extern "C" PERFTOOLS_DLL_DECL void tc_delete_aligned(void* p, std::align_val_t) PERFTOOLS_NOTHROW
{
  free_fast_path(p);
}

// There is no easy way to obtain the actual size used by do_memalign to allocate aligned storage, so for now
// just ignore the size. It might get useful in the future.
extern "C" PERFTOOLS_DLL_DECL void tc_delete_sized_aligned(void* p, size_t size, std::align_val_t align) PERFTOOLS_NOTHROW
{
  free_fast_path(p);
}

extern "C" PERFTOOLS_DLL_DECL void tc_delete_aligned_nothrow(void* p, std::align_val_t, const std::nothrow_t&) PERFTOOLS_NOTHROW
{
  free_fast_path(p);
}

extern "C" PERFTOOLS_DLL_DECL
void tc_free_aligned_sized(void *ptr, size_t, size_t) PERFTOOLS_NOTHROW {
  free_fast_path(ptr);
}

extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_aligned(size_t size, std::align_val_t align)
#ifdef TC_ALIAS
TC_ALIAS(tc_new_aligned);
#else
{
  return memalign_fast_path(static_cast(align), size);
}
#endif

extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_aligned_nothrow(size_t size, std::align_val_t align, const std::nothrow_t& nt) PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_new_aligned_nothrow);
#else
{
  return memalign_fast_path(static_cast(align), size);
}
#endif

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_aligned(void* p, std::align_val_t) PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_delete_aligned);
#else
{
  free_fast_path(p);
}
#endif

// There is no easy way to obtain the actual size used by do_memalign to allocate aligned storage, so for now
// just ignore the size. It might get useful in the future.
extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_sized_aligned(void* p, size_t size, std::align_val_t align) PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_delete_sized_aligned);
#else
{
  free_fast_path(p);
}
#endif

extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_aligned_nothrow(void* p, std::align_val_t, const std::nothrow_t&) PERFTOOLS_NOTHROW
#ifdef TC_ALIAS
TC_ALIAS(tc_delete_aligned_nothrow);
#else
{
  free_fast_path(p);
}
#endif

static size_t pagesize = 0;

extern "C" PERFTOOLS_DLL_DECL void* tc_valloc(size_t size) PERFTOOLS_NOTHROW {
  // Allocate page-aligned object of length >= size bytes
  if (pagesize == 0) pagesize = getpagesize();
  return tc_memalign(pagesize, size);
}

extern "C" PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t size) PERFTOOLS_NOTHROW {
  // Round up size to a multiple of pagesize
  if (pagesize == 0) pagesize = getpagesize();
  if (size == 0) {     // pvalloc(0) should allocate one page, according to
    size = pagesize;   // http://man.free4web.biz/man3/libmpatrol.3.html
  }
  size = (size + pagesize - 1) & ~(pagesize - 1);
  return tc_memalign(pagesize, size);
}

extern "C" PERFTOOLS_DLL_DECL void tc_malloc_stats(void) PERFTOOLS_NOTHROW {
  do_malloc_stats();
}

extern "C" PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) PERFTOOLS_NOTHROW {
  return do_mallopt(cmd, value);
}

#if GPERFTOOLS_HAS_MALLINFO
extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) PERFTOOLS_NOTHROW {
  return do_mallinfo();
}
#endif

#if GPERFTOOLS_HAS_MALLINFO2
extern "C" PERFTOOLS_DLL_DECL struct mallinfo2 tc_mallinfo2(void) PERFTOOLS_NOTHROW {
  return do_mallinfo();
}
#endif

extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) PERFTOOLS_NOTHROW {
  return MallocExtension::instance()->GetAllocatedSize(ptr);
}

extern "C" PERFTOOLS_DLL_DECL void* tc_malloc_skip_new_handler(size_t size)  PERFTOOLS_NOTHROW {
  void* result = do_malloc(size);
  tcmalloc::InvokeNewHook(result, size);
  return result;
}

#endif  // TCMALLOC_USING_DEBUGALLOCATION
gperftools-gperftools-2.18/src/tcmalloc_guard.h000066400000000000000000000042231513545575200217470ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// We expose the TCMallocGuard class -- which initializes the tcmalloc
// allocator -- so classes that need to be sure tcmalloc is loaded
// before they do stuff -- notably heap-profiler -- can.  To use this
// create a static TCMallocGuard instance at the top of a file where
// you need tcmalloc to be initialized before global constructors run.

#ifndef TCMALLOC_TCMALLOC_GUARD_H_
#define TCMALLOC_TCMALLOC_GUARD_H_

class TCMallocGuard {
 public:
  TCMallocGuard();
  ~TCMallocGuard();
};

#endif  // TCMALLOC_TCMALLOC_GUARD_H_
gperftools-gperftools-2.18/src/tcmalloc_internal.h000066400000000000000000000060611513545575200224630ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein 
//
// Some obscure memory-allocation routines may not be declared on all
// systems.  In those cases, we'll just declare them ourselves.
// This file is meant to be used only internally, for unittests.

#include 

#ifndef _XOPEN_SOURCE
# define _XOPEN_SOURCE 600  // for posix_memalign
#endif
#include          // for posix_memalign
// FreeBSD has malloc.h, but complains if you use it
#if defined(HAVE_MALLOC_H) && !defined(__FreeBSD__)
#include          // for memalign, valloc, pvalloc
#endif

#include 

#include "base/basictypes.h"

// __THROW is defined in glibc systems.  It means, counter-intuitively,
// "This function will never throw an exception."  It's an optional
// optimization tool, but we may need to use it to match glibc prototypes.
#ifndef __THROW    // I guess we're not on a glibc system
# define __THROW   // __THROW is just an optimization, so ok to make it ""
#endif

#if !HAVE_DECL_POSIX_MEMALIGN
extern "C" int posix_memalign(void** ptr, size_t align, size_t size) __THROW;
#endif
#if !HAVE_DECL_MEMALIGN
extern "C" void* memalign(size_t __alignment, size_t __size) __THROW;
#endif
#if !HAVE_DECL_VALLOC
extern "C" void* valloc(size_t __size) __THROW;
#endif
#if !HAVE_DECL_PVALLOC
extern "C" void* pvalloc(size_t __size) __THROW;
#endif

// Implemented in tcmalloc.cc or debugallocation.cc
ATTRIBUTE_VISIBILITY_HIDDEN void SetupMallocExtension();
gperftools-gperftools-2.18/src/testing_portal.h000066400000000000000000000064701513545575200220330ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef TESTING_PORTAL_H_
#define TESTING_PORTAL_H_
#include "config.h"

#include 
#include 

#include 

#include "base/function_ref.h"
#include "base/basictypes.h"

namespace tcmalloc {

class ATTRIBUTE_VISIBILITY_HIDDEN TestingPortal {
public:
  static inline constexpr char kMagic[] = "tcmalloc.impl.testing-portal";
  static TestingPortal* Get() {
    static TestingPortal* instance = ([] () {
      struct {
        TestingPortal* ptr = nullptr;
        size_t v = 0;
      } s;
      bool ok = MallocExtension::instance()->GetNumericProperty(kMagic, &s.v);
      if (!ok || s.ptr == nullptr) {
        abort();
      }
      return s.ptr;
    })();

    return instance;
  }
  static TestingPortal** CheckGetPortal(const char* property_name, size_t* value) {
    if (strcmp(property_name, kMagic) != 0) {
      return nullptr;
    }
    return reinterpret_cast(value) - 1;
  }

  virtual bool HaveSystemRelease() = 0;
  virtual bool IsDebuggingMalloc() = 0;
  virtual size_t GetPageSize() = 0;
  virtual size_t GetMinAlign() = 0;
  virtual size_t GetMaxSize() = 0;
  virtual int64_t& GetSampleParameter() = 0;
  virtual double& GetReleaseRate() = 0;
  virtual int32_t& GetMaxFreeQueueSize() = 0;

  virtual bool HasEmergencyMalloc() = 0;
  virtual bool IsEmergencyPtr(void* ptr) = 0;
  virtual void WithEmergencyMallocEnabled(FunctionRef body) = 0;

  virtual uint32_t GetSizeClass(void* ptr) = 0;

  virtual void* RunReallocWithCallback(
    void* old_ptr, size_t new_size,
    void (*invalid_free_fn)(void*),
    size_t (*invalid_get_size_fn)(const void*)) = 0;

protected:
  virtual ~TestingPortal();
};

}  // namespace tcmalloc

#endif  // TESTING_PORTAL_H_
gperftools-gperftools-2.18/src/tests/000077500000000000000000000000001513545575200177575ustar00rootroot00000000000000gperftools-gperftools-2.18/src/tests/addressmap_unittest.cc000066400000000000000000000130071513545575200243510ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
#include "config_for_unittests.h"

#include "addressmap-inl.h"

#include 

#include 
#include 
#include 
#include 
#include 

#include "gtest/gtest.h"

// pair of associated value and object size
typedef std::pair ValueT;

struct PtrAndSize {
  std::unique_ptr ptr;
  size_t size;

  PtrAndSize(char* p, size_t s) : ptr(p), size(s) {}
};

size_t SizeFunc(const ValueT& v) { return v.second; }

TEST(AddressMapUnittest, Basic) {
  constexpr int N = 100000;
  constexpr int kIters = 20;
  constexpr int kMaxRealSize = 49;
  // 100Mb to stress not finding previous object (AddressMap's cluster is 1Mb):
  constexpr size_t kMaxSize = 100 << 20;

  std::mt19937 rng(0);

  // generates uniformly distributed size_t in range [0, n)
  auto uniform = [&] (size_t n) -> size_t {
    return std::uniform_int_distribution{0, n-1}(rng);
  };

  std::vector ptrs_and_sizes;
  ptrs_and_sizes.reserve(N);
  for (int i = 0; i < N; ++i) {
    size_t s = uniform(kMaxRealSize-1) + 1;
    ptrs_and_sizes.emplace_back(new char[s], s);
  }

  for (int x = 0; x < kIters; ++x) {
    printf("Iteration %d/%d...\n", x, kIters);

    // Permute pointers to get rid of allocation order issues
    std::shuffle(ptrs_and_sizes.begin(), ptrs_and_sizes.end(), rng);

    AddressMap map(malloc, free);
    const ValueT* result;
    const void* res_p;

    // Insert a bunch of entries
    for (int i = 0; i < N; ++i) {
      char* p = ptrs_and_sizes[i].ptr.get();
      ASSERT_FALSE(map.Find(p));
      int offs = uniform(ptrs_and_sizes[i].size);
      ASSERT_FALSE(map.FindInside(&SizeFunc, kMaxSize, p + offs, &res_p));
      map.Insert(p, std::make_pair(i, ptrs_and_sizes[i].size));
      ASSERT_TRUE(result = map.Find(p));
      ASSERT_EQ(result->first, i);
      ASSERT_TRUE(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p));
      ASSERT_EQ(res_p, p);
      ASSERT_EQ(result->first, i);
      map.Insert(p, std::make_pair(i + N, ptrs_and_sizes[i].size));
      ASSERT_TRUE(result = map.Find(p));
      ASSERT_EQ(result->first, i + N);
    }

    // Delete the even entries
    for (int i = 0; i < N; i += 2) {
      void* p = ptrs_and_sizes[i].ptr.get();
      ValueT removed;
      ASSERT_TRUE(map.FindAndRemove(p, &removed));
      ASSERT_EQ(removed.first, i + N);
    }

    // Lookup the odd entries and adjust them
    for (int i = 1; i < N; i += 2) {
      char* p = ptrs_and_sizes[i].ptr.get();
      ASSERT_TRUE(result = map.Find(p));
      ASSERT_EQ(result->first, i + N);
      int offs = uniform(ptrs_and_sizes[i].size);
      ASSERT_TRUE(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p));
      ASSERT_EQ(res_p, p);
      ASSERT_EQ(result->first, i + N);
      map.Insert(p, std::make_pair(i + 2*N, ptrs_and_sizes[i].size));
      ASSERT_TRUE(result = map.Find(p));
      ASSERT_EQ(result->first, i + 2*N);
    }

    // Insert even entries back
    for (int i = 0; i < N; i += 2) {
      char* p = ptrs_and_sizes[i].ptr.get();
      int offs = uniform(ptrs_and_sizes[i].size);
      ASSERT_TRUE(!map.FindInside(&SizeFunc, kMaxSize, p + offs, &res_p));
      map.Insert(p, std::make_pair(i + 2*N, ptrs_and_sizes[i].size));
      ASSERT_TRUE(result = map.Find(p));
      ASSERT_EQ(result->first, i + 2*N);
      ASSERT_TRUE(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p));
      ASSERT_EQ(res_p, p);
      ASSERT_EQ(result->first, i + 2*N);
    }

    // Check all entries
    std::set > check_set;
    map.Iterate([&] (const void* ptr, ValueT* val) {
      check_set.insert(std::make_pair(ptr, val->first));
    });
    ASSERT_EQ(check_set.size(), N);
    for (int i = 0; i < N; ++i) {
      void* p = ptrs_and_sizes[i].ptr.get();
      check_set.erase(std::make_pair(p, i + 2*N));
      ASSERT_TRUE(result = map.Find(p));
      ASSERT_EQ(result->first, i + 2*N);
    }
    ASSERT_EQ(check_set.size(), 0);
  }
}
gperftools-gperftools-2.18/src/tests/check_address_test.cc000066400000000000000000000065121513545575200241130ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2023, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config_for_unittests.h"

#include "base/logging.h"
#include "base/spinlock.h" // IWYU pragma: keep

#include "check_address-inl.h"

#ifdef CHECK_ADDRESS_USES_SIGPROCMASK
#define CheckAddress CheckAddressPipes
#define FORCE_PIPES
#include "check_address-inl.h"
#undef CheckAddress
#undef FORCE_PIPES
#endif

#ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
#endif

#include "gtest/gtest.h"

#include "tests/testutil.h"

void* unreadable = ([] () {
  void* rv = mmap(nullptr, getpagesize(), PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  if (rv == MAP_FAILED) {
    abort();
  }
  return rv;
})();

void TestFn(bool (*access_check_fn)(uintptr_t,int)) {
  int pagesize = getpagesize();

  ASSERT_FALSE(access_check_fn(0, pagesize));
  ASSERT_TRUE(access_check_fn(reinterpret_cast(&pagesize), pagesize));

  ASSERT_FALSE(access_check_fn(reinterpret_cast(unreadable), pagesize));

  for (int i = (256 << 10); i > 0; i--) {
    // Lets ensure that pipes access method is forced eventually to drain pipe
    ASSERT_TRUE(noopt(access_check_fn)(reinterpret_cast(&pagesize), pagesize));
  }
}

TEST(CheckAddressTest, MainAccess) {
  ASSERT_NO_FATAL_FAILURE(TestFn([] (uintptr_t a, int ps) {
    // note, this looks odd, but we do it so that each access_check_fn
    // call above reads CheckAddress freshly.
    return CheckAddress(a, ps);
  }));

#ifdef CHECK_ADDRESS_USES_SIGPROCMASK
  ASSERT_EQ(CheckAddress, CheckAccessSingleSyscall);
#endif
}

#ifdef CHECK_ADDRESS_USES_SIGPROCMASK
TEST(CheckAddressTest, PipesAccess) {
  ASSERT_NO_FATAL_FAILURE(TestFn(CheckAddressPipes));
}
TEST(CheckAddressPipes, TwoSyscalls) {
  ASSERT_NO_FATAL_FAILURE(TestFn(CheckAccessTwoSyscalls));
}
#endif  // CHECK_ADDRESS_USES_SIGPROCMASK
gperftools-gperftools-2.18/src/tests/cleanup_test.cc000066400000000000000000000042351513545575200227600ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config_for_unittests.h"

#include "base/cleanup.h"

#include "gtest/gtest.h"

TEST(CleanupTest, Basic) {
  bool cleanup_ran = false;
  {
    tcmalloc::Cleanup cleanup([&] () {
      cleanup_ran = true;
    });
  }

  ASSERT_TRUE(cleanup_ran);
}

TEST(CleanupTest, CleanupReturn) {
  int cleanup_ran = 0;
  int armed = 0;

  {
    tcmalloc::Cleanup cleanup = ([&] {
      armed++;
      return tcmalloc::Cleanup([&] () {
        cleanup_ran++;
      });
    })();

    ASSERT_EQ(cleanup_ran, 0);
    ASSERT_EQ(armed, 1);
  }

  ASSERT_EQ(cleanup_ran, 1);
}
gperftools-gperftools-2.18/src/tests/current_allocated_bytes_test.cc000066400000000000000000000051631513545575200262320ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
//
// Author: Craig Silverstein

// This tests the accounting done by tcmalloc.  When we allocate and
// free a small buffer, the number of bytes used by the application
// before the alloc+free should match the number of bytes used after.
// However, the internal data structures used by tcmalloc will be
// quite different -- new spans will have been allocated, etc.  This
// is, thus, a simple test that we account properly for the internal
// data structures, so that we report the actual application-used
// bytes properly.

#include "config_for_unittests.h"

#include 

#include "gtest/gtest.h"

TEST(CurrentAllocatedBytes, Basic) {
  static constexpr char kCurrent[] = "generic.current_allocated_bytes";

  size_t before_bytes, after_bytes;
  ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty(kCurrent, &before_bytes));
  (::operator delete)((::operator new)(200));
  ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty(kCurrent, &after_bytes));

  ASSERT_EQ(before_bytes, after_bytes);
}
gperftools-gperftools-2.18/src/tests/debugallocation_test.cc000066400000000000000000000251761513545575200244740ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Fred Akalin

#include "config_for_unittests.h"

#include 
#include 
#include  // for memcmp

#include "gperftools/malloc_extension.h"
#include "gperftools/tcmalloc.h"

#include "base/basictypes.h"
#include "base/logging.h"
#include "testing_portal.h"
#include "tests/testutil.h"

#include "gtest/gtest.h"

using tcmalloc::TestingPortal;

// Test match as well as mismatch rules.  But do not test on OS X; on
// OS X the OS converts new/new[] to malloc before it gets to us, so
// we are unable to catch these mismatch errors.
#ifndef __APPLE__
TEST(DebugAllocationTest, DeallocMismatch) {
  // malloc can be matched only by free
  // new can be matched only by delete and delete(nothrow)
  // new[] can be matched only by delete[] and delete[](nothrow)
  // new(nothrow) can be matched only by delete and delete(nothrow)
  // new(nothrow)[] can be matched only by delete[] and delete[](nothrow)

  // Allocate with malloc.
  {
    int* x = static_cast(noopt(malloc(sizeof(*x))));
    EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
    EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
    // Should work fine.
    free(x);
  }

  // Allocate with new.
  {
    int* x = noopt(new int);
    int* y = noopt(new int);
    EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
    EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
    delete x;
    ::operator delete(y, std::nothrow);
  }

  // Allocate with new[].
  {
    int* x = noopt(new int[1]);
    int* y = noopt(new int[1]);
    EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
    EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
    delete [] x;
    ::operator delete[](y, std::nothrow);
  }

  // Allocate with new(nothrow).
  {
    int* x = noopt(new (std::nothrow) int);
    int* y = noopt(new (std::nothrow) int);
    EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
    EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
    delete x;
    ::operator delete(y, std::nothrow);
  }

  // Allocate with new(nothrow)[].
  {
    int* x = noopt(new (std::nothrow) int[1]);
    int* y = noopt(new (std::nothrow) int[1]);
    EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
    EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
    delete [] x;
    ::operator delete[](y, std::nothrow);
  }
}
#endif  // #ifdef OS_MACOSX

TEST(DebugAllocationTest, DoubleFree) {
  int* pint = noopt(new int);
  delete pint;
  EXPECT_DEATH(delete pint, "has been already deallocated");
}

TEST(DebugAllocationTest, StompBefore) {
  int* pint = noopt(new int);
  (void)pint;
  pint[-1] = 5;
  EXPECT_DEATH(delete pint, "a word before object");
}

TEST(DebugAllocationTest, StompAfter) {
  int* pint = noopt(new int);
  (void)pint;
  pint[1] = 5;
  EXPECT_DEATH(delete pint, "a word after object");
}

TEST(DebugAllocationTest, FreeQueueTest) {
  // Verify that the allocator doesn't return blocks that were recently freed.
  int* x = noopt(new int);
  int* old_x = x;
  delete x;
  x = noopt(new int);
  #if 1
    // This check should not be read as a universal guarantee of behavior.  If
    // other threads are executing, it would be theoretically possible for this
    // check to fail despite the efforts of debugallocation.cc to the contrary.
    // It should always hold under the controlled conditions of this unittest,
    // however.
    EXPECT_NE(x, old_x);  // Allocator shouldn't return recently freed blocks
  #else
    // The below check passes, but since it isn't *required* to pass, I've left
    // it commented out.
    // EXPECT_EQ(x, old_x);
  #endif
  old_x = nullptr;  // avoid breaking opt build with an unused variable warning.
  delete x;
}

TEST(DebugAllocationTest, DanglingPointerWriteTest) {
  // This test can only be run if debugging.
  //
  // If not debugging, the 'new' following the dangling write might not be
  // safe.  When debugging, we expect the (trashed) deleted block to be on the
  // list of recently-freed blocks, so the following 'new' will be safe.
#if 1
  int* x = noopt(new int);
  delete x;
  int poisoned_x_value = *x;
  *x = 1;  // a dangling write.

  char* s = noopt(new char[TestingPortal::Get()->GetMaxFreeQueueSize()]);
  // When we delete s, we push the storage that was previously allocated to x
  // off the end of the free queue.  At that point, the write to that memory
  // will be detected.
  EXPECT_DEATH(delete [] s, "Memory was written to after being freed.");

  // restore the poisoned value of x so that we can delete s without causing a
  // crash.
  *x = poisoned_x_value;
  delete [] s;
#endif
}

TEST(DebugAllocationTest, DanglingWriteAtExitTest) {
  int *x = noopt(new int);
  delete x;
  int old_x_value = *x;
  *x = 1;
  // verify that dangling writes are caught at program termination if the
  // corrupted block never got pushed off of the end of the free queue.
  EXPECT_DEATH(exit(0), "Memory was written to after being freed.");
  *x = old_x_value;  // restore x so that the test can exit successfully.
}

namespace FooBar {
ATTRIBUTE_NOINLINE
void StackTraceMarker(int *x) {
  (::operator delete)(x);
  // prevent tail-call above
  noopt(x);
}
}  // namespace FooBar

TEST(DebugAllocationTest, StackTraceWithDanglingWriteAtExitTest) {
  int *x = noopt(new int);
  FooBar::StackTraceMarker(x);
  int old_x_value = *x;
  *x = 1;
  if (!getenv("TCM_DEBUG_BT_SYMBOLIZATION_TEST")) {
    // verify that we also get a stack trace when we have a dangling write.
    // The " @ " is part of the stack trace output.
    EXPECT_DEATH(exit(0), " @ .*FooBar::StackTraceMarker");
    *x = old_x_value;  // restore x so that the test can exit successfully.
  } else {
    exit(0);
  }
}

static size_t CurrentlyAllocatedBytes() {
  size_t value;
  CHECK(MallocExtension::instance()->GetNumericProperty(
            "generic.current_allocated_bytes", &value));
  return value;
}

TEST(DebugAllocationTest, CurrentlyAllocated) {
  // Clear the free queue
#if 1
  TestingPortal::Get()->GetMaxFreeQueueSize() = 0;
  // Force a round-trip through the queue management code so that the
  // new size is seen and the queue of recently-freed blocks is flushed.
  free(noopt(malloc(1)));
  TestingPortal::Get()->GetMaxFreeQueueSize() = 1048576;
#endif

  // Free something and check that it disappears from allocated bytes
  // immediately.
  char* p = noopt(new char[1000]);
  size_t after_malloc = CurrentlyAllocatedBytes();
  delete[] p;
  size_t after_free = CurrentlyAllocatedBytes();
  EXPECT_LE(after_free, after_malloc - 1000);
}

TEST(DebugAllocationTest, GetAllocatedSizeTest) {
  // When debug_allocation is in effect, GetAllocatedSize should return
  // exactly requested size, since debug_allocation doesn't allow users
  // to write more than that.
  for (int i = 0; i < 10; ++i) {
#ifdef __APPLE__
    if (i == 0) continue;
#endif
    void *p = noopt(malloc(i));
    EXPECT_EQ(i, MallocExtension::instance()->GetAllocatedSize(p));
    free(p);

    p = tc_memalign(16, i);
    auto amount = MallocExtension::instance()->GetAllocatedSize(p);
    EXPECT_LE(i, amount);
    memset(p, 0xff, amount);
    tc_free(p);
  }

  void* a = noopt(malloc(1000));
  EXPECT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000);
  // This is just a sanity check.  If we allocated too much, alloc is broken
  EXPECT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000);
  free(a);

  EXPECT_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000), 1000);

  a = tc_memalign(16, 1000);
  auto amount = MallocExtension::instance()->GetAllocatedSize(a);
  EXPECT_GE(amount, 1000);
  // This is just a sanity check.  If we allocated too much, alloc is broken
  EXPECT_LE(amount, 5000);
  memset(a, 0xff, amount);
  tc_free(a);
}

TEST(DebugAllocationTest, HugeAlloc) {
  // This must not be a const variable so it doesn't form an
  // integral-constant-expression which can be *statically* rejected by the
  // compiler as too large for the allocation.
  size_t kTooBig = ~static_cast(0);
  void* a = nullptr;

  (void)kTooBig;
  (void)a;

  a = noopt(malloc(noopt(kTooBig)));
  EXPECT_EQ(nullptr, a);

  // kAlsoTooBig is small enough not to get caught by debugallocation's check,
  // but will still fall through to tcmalloc's check. This must also be
  // a non-const variable. See kTooBig for more details.
  size_t kAlsoTooBig = kTooBig - 1024;

  a = noopt(malloc(noopt(kAlsoTooBig)));
  EXPECT_EQ(nullptr, a);
}

// based on test program contributed by mikesart@gmail.com aka
// mikesart@valvesoftware.com. See issue-464.
TEST(DebugAllocationTest, ReallocAfterMemalign) {
  char stuff[50];
  memset(stuff, 0x11, sizeof(stuff));
  void *p = tc_memalign(16, sizeof(stuff));
  EXPECT_NE(p, nullptr);
  memcpy(stuff, p, sizeof(stuff));

  p = noopt(realloc(p, sizeof(stuff) + 10));
  EXPECT_NE(p, nullptr);

  int rv = memcmp(stuff, p, sizeof(stuff));
  EXPECT_EQ(rv, 0);
}

int main(int argc, char** argv) {
#if __APPLE__
  // OSX needs dsymutil crap
  std::string cmd = "dsymutil ";
  cmd += argv[0];
  int result = system(cmd.c_str());
  printf("OSX-specific '%s' -> %d\n", cmd.c_str(), result);
#endif

  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
gperftools-gperftools-2.18/src/tests/for_each_line_test.cc000066400000000000000000000162271513545575200241120ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2025, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config_for_unittests.h"

#include "base/for_each_line.h"

#include 

#include 
#include 

#include "gtest/gtest.h"

static constexpr const char* kBasicExample[] = {
  "short",
  "562c039e8000-562c039f0000 r--p 00000000 00:00 2354112436 /home/me/src/External/gperftools/proc_maps_iterator_test",
  "562c039f0000-562c03a35000 r-xp 00008000 00:00 2354112436 /home/me/src/External/gperftools/proc_maps_iterator_test",
  "562c03a35000-562c03a4b000 r--p 0004d000 00:00 2354112436 /home/me/src/External/gperftools/proc_maps_iterator_test",
  "562c03a4b000-562c03a4d000 r--p 00062000 00:00 2354112436 /home/me/src/External/gperftools/proc_maps_iterator_test",
  "562c03a4d000-562c03a4e000 rw-p 00064000 00:00 2354112436 /home/me/src/External/gperftools/proc_maps_iterator_test",
  "562c1f8fc000-562c1f91d000 rw-p 00000000 00:00 0 [heap]",
  "7f7987aed000-7f7987b15000 r--p 00000000 00:00 1395652429 /usr/lib/x86_64-linux-gnu/libc.so.6",
  "7f7987b15000-7f7987c7a000 r-xp 00028000 00:00 1395652429 /usr/lib/x86_64-linux-gnu/libc.so.6",
  "7f7987c7a000-7f7987cd0000 r--p 0018d000 00:00 1395652429 /usr/lib/x86_64-linux-gnu/libc.so.6",
  "7f7987cd0000-7f7987cd4000 r--p 001e2000 00:00 1395652429 /usr/lib/x86_64-linux-gnu/libc.so.6",
  "7f7987cd4000-7f7987cd6000 rw-p 001e6000 00:00 1395652429 /usr/lib/x86_64-linux-gnu/libc.so.6",
  "7f7987cd6000-7f7987ce3000 rw-p 00000000 00:00 0",
  "7f7987ce3000-7f7987ce7000 r--p 00000000 00:00 1338727929 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1",
  "7f7987ce7000-7f7987d0a000 r-xp 00004000 00:00 1338727929 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1",
  "7f7987d0a000-7f7987d0e000 r--p 00027000 00:00 1338727929 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1",
  "7f7987d0e000-7f7987d0f000 r--p 0002a000 00:00 1338727929 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1",
  "7f7987d0f000-7f7987d10000 rw-p 0002b000 00:00 1338727929 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1",
  "7f7987d10000-7f7987d21000 r--p 00000000 00:00 1395652475 /usr/lib/x86_64-linux-gnu/libm.so.6",
  "7f7987d21000-7f7987d9e000 r-xp 00011000 00:00 1395652475 /usr/lib/x86_64-linux-gnu/libm.so.6",
  "7f7987d9e000-7f7987dfe000 r--p 0008e000 00:00 1395652475 /usr/lib/x86_64-linux-gnu/libm.so.6",
  "7f7987dfe000-7f7987dff000 r--p 000ed000 00:00 1395652475 /usr/lib/x86_64-linux-gnu/libm.so.6",
  "7f7987dff000-7f7987e00000 rw-p 000ee000 00:00 1395652475 /usr/lib/x86_64-linux-gnu/libm.so.6",
  "7f7987e00000-7f7987ea2000 r--p 00000000 00:00 1338726433 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.34",
  "7f7987ea2000-7f7987fd2000 r-xp 000a2000 00:00 1338726433 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.34",
  "7f7987fd2000-7f7988060000 r--p 001d2000 00:00 1338726433 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.34",
  "7f7988060000-7f798806f000 r--p 0025f000 00:00 1338726433 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.34",
  "7f798806f000-7f7988072000 rw-p 0026e000 00:00 1338726433 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.34",
  "7f7988072000-7f7988076000 rw-p 00000000 00:00 0",
  "7f7988082000-7f7988087000 rw-p 00000000 00:00 0",
  "7f79880b5000-7f79880b7000 rw-p 00000000 00:00 0",
  "7f79880b7000-7f79880bb000 r--p 00000000 00:00 0 [vvar]",
  "7f79880bb000-7f79880bd000 r--p 00000000 00:00 0 [vvar_vclock]",
  "7f79880bd000-7f79880bf000 r-xp 00000000 00:00 0 [vdso]",
  "7f79880bf000-7f79880c0000 r--p 00000000 00:00 1338729117 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
  "7f79880c0000-7f79880e8000 r-xp 00001000 00:00 1338729117 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
  "7f79880e8000-7f79880f3000 r--p 00029000 00:00 1338729117 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
  "7f79880f3000-7f79880f5000 r--p 00034000 00:00 1338729117 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
  "7f79880f5000-7f79880f6000 rw-p 00036000 00:00 1338729117 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
  "7f79880f6000-7f79880f7000 rw-p 00000000 00:00 0",
  "7fff4dd6c000-7fff4dd8d000 rw-p 00000000 00:00 0 [stack]"
};

struct StringReader {
  mutable std::string_view sv;
  explicit StringReader(std::string_view sv) : sv{sv} {}
  int operator()(void* buf, int count) const {
    count = std::min(count, sv.size());
    memcpy(buf, sv.data(), count);
    sv.remove_prefix(count);
    return count;
  }
};

class ForEachLineTest : public testing::Test {
protected:
  ForEachLineTest() : lines_{kBasicExample, kBasicExample + arraysize(kBasicExample)} {
    for (const std::string& l : lines_) {
      example_.append(l).push_back('\n');
    }
  }

  void CompareEachLine() {
    int i = 0;
    tcmalloc::ForEachLine<120>(StringReader{example_},
                               [&] (char* begin, char* end) -> bool {
                                 std::string_view l{begin, static_cast(end - begin)};
                                 // printf("l: %.*s\n", (int)l.size(), l.data());
                                 EXPECT_EQ(l, lines_[i++]);
                                 return true;
                               });
    // printf("checked %d lines\n", i);
    EXPECT_EQ(i, 41);
  }

  const std::vector lines_;
  std::string example_;
};

TEST_F(ForEachLineTest, Basic) {
  CompareEachLine();
}

TEST_F(ForEachLineTest, NoLastEOL) {
  EXPECT_EQ(*example_.rbegin(), '\n');
  example_.pop_back(); // remove last \n
  EXPECT_NE(*example_.rbegin(), '\n');

  CompareEachLine();
}

TEST_F(ForEachLineTest, ShortBuffer) {
  std::vector got;
  bool ok = tcmalloc::ForEachLine<20>(
    StringReader{example_},
    [&] (char* begin, char* end) -> bool {
      got.emplace_back(begin, static_cast(end - begin));
      return true;
    });
  EXPECT_EQ(ok, false);
  EXPECT_EQ(got.size(), 1);
}
gperftools-gperftools-2.18/src/tests/frag_unittest.cc000066400000000000000000000077661513545575200231640ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2003, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// Test speed of handling fragmented heap

#include "config_for_unittests.h"

#include 

#include 
#include 
#include 

#include 
#include 
#include 

#include "testing_portal.h"
#include "tests/testutil.h"

#include "gtest/gtest.h"

using tcmalloc::TestingPortal;

static double GetCPUTime() {
  // Note, we do plain wall-clock time instead of cpu time, but this
  // is close enough for this file's purpose.
  return clock() / static_cast(CLOCKS_PER_SEC);
}

static std::optional GetSlackBytes() {
  size_t slack;
  if (!MallocExtension::instance()->GetNumericProperty(
        "tcmalloc.slack_bytes",
        &slack)) {
    return {};
  }
  return slack;
}

TEST(FragTest, Slack) {
  TestingPortal* portal = TestingPortal::Get();

  // Make kAllocSize one page larger than the maximum small object size.
  const int kAllocSize = portal->GetMaxSize() + portal->GetPageSize();
  // Allocate 400MB in total.
  const int kTotalAlloc = 400 << 20;
  const int kAllocIterations = kTotalAlloc / kAllocSize;

  // Allocate lots of objects
  std::vector> saved;
  saved.reserve(kAllocIterations);
  for (int i = 0; i < kAllocIterations; i++) {
    saved.emplace_back(noopt(new char[kAllocSize]));
  }

  // Check the current "slack".
  size_t slack_before = GetSlackBytes().value();

  // Free alternating ones to fragment heap
  size_t free_bytes = 0;
  for (int i = 0; i < saved.size(); i += 2) {
    saved[i].reset();
    free_bytes += kAllocSize;
  }

  // Check that slack delta is within 10% of expected.
  size_t slack_after = GetSlackBytes().value();

  ASSERT_GE(slack_after, slack_before);
  size_t slack = slack_after - slack_before;

  ASSERT_GT(double(slack), 0.9*free_bytes);
  ASSERT_LT(double(slack), 1.1*free_bytes);

  // Dump malloc stats
  static const int kBufSize = 1<<20;
  char* buffer = new char[kBufSize];
  MallocExtension::instance()->GetStats(buffer, kBufSize);
  puts(buffer);
  delete[] buffer;

  // Now do timing tests
  for (int i = 0; i < 5; i++) {
    static constexpr int kIterations = 100000;
    double start = GetCPUTime();

    for (int i = 0; i < kIterations; i++) {
      size_t s = GetSlackBytes().value();
      (void)s;
    }

    double end = GetCPUTime();
    fprintf(stderr, "getproperty: %6.1f ns/call\n",
            (end-start) * 1e9 / kIterations);
  }
}
gperftools-gperftools-2.18/src/tests/function_ref_test.cc000066400000000000000000000066501513545575200240150ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config_for_unittests.h"

#include "base/function_ref.h"

#include 
#include 

#include "gtest/gtest.h"

TEST(FunctionRef, Basic) {
  int fn_ref_invoked = 0;
  int fn_result = -1;
  int fn_arg = 42;

  auto fn = [&] (tcmalloc::FunctionRef ref) {
    fn_result = ref(fn_arg);
    fn_ref_invoked++;
  };

  fn([] (int arg) -> int {
    return arg;
  });

  ASSERT_EQ(fn_result, 42);
  ASSERT_EQ(fn_ref_invoked, 1);

  fn_arg = 13;

  fn([fn_ref_invoked, no_copy = std::make_unique(1)] (int arg) {
    return fn_ref_invoked + arg;
  });

  ASSERT_EQ(fn_result, 14);
  ASSERT_EQ(fn_ref_invoked, 2);

  auto body = [fn_ref_invoked, no_copy = std::make_unique(1)] (int arg) {
    return fn_ref_invoked + arg;
  };

  fn(body);

  ASSERT_EQ(fn_result, 15);
  ASSERT_EQ(fn_ref_invoked, 3);

  std::function f = [&] (int arg) { return fn_ref_invoked + arg; };

  fn(f);

  ASSERT_EQ(fn_result, 16);
  ASSERT_EQ(fn_ref_invoked, 4);
}

TEST(FunctionRef, BasicFirstDataArg) {
  int fn_ref_invoked = 0;
  int fn_result = -1;
  int fn_arg = 42;

  auto fn = [&] (tcmalloc::FunctionRefFirstDataArg ref) {
    fn_result = ref(fn_arg);
    fn_ref_invoked++;
  };

  fn([] (int arg) -> int {
    return arg;
  });

  ASSERT_EQ(fn_result, 42);
  ASSERT_EQ(fn_ref_invoked, 1);

  fn_arg = 13;

  fn([fn_ref_invoked, no_copy = std::make_unique(1)] (int arg) {
    return fn_ref_invoked + arg;
  });

  ASSERT_EQ(fn_result, 14);
  ASSERT_EQ(fn_ref_invoked, 2);

  auto body = [fn_ref_invoked, no_copy = std::make_unique(1)] (int arg) {
    return fn_ref_invoked + arg;
  };

  fn(body);

  ASSERT_EQ(fn_result, 15);
  ASSERT_EQ(fn_ref_invoked, 3);

  std::function f = [&] (int arg) { return fn_ref_invoked + arg; };

  fn(f);

  ASSERT_EQ(fn_result, 16);
  ASSERT_EQ(fn_ref_invoked, 4);
}
gperftools-gperftools-2.18/src/tests/generic_writer_test.cc000066400000000000000000000035171513545575200243430ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
#include "config_for_unittests.h"

#include "base/generic_writer.h"

#include 
#define _USE_MATH_DEFINES
#include 

#include 

#include "gtest/gtest.h"

using tcmalloc::GenericWriter;

constexpr int kLargeAmount = 128 << 10;

std::string expected_output = ([] () {
  std::string s = "Answer is 42\nPI is 3.141593\n";
  s = s + s;
  s.resize(kLargeAmount, 'X');
  return s;
})();

void PrintLargeAmount(GenericWriter* writer) {
  char initial[256];
  int rv = snprintf(initial, sizeof(initial), "Answer is %d\nPI is %.6f\n", 42, M_PI);
  EXPECT_LT(rv, sizeof(initial));

  writer->AppendF("Answer is %d\nPI is %.6f\n", 42, M_PI);
  writer->AppendStr(initial);

  int rest_amount = kLargeAmount - strlen(initial) * 2;

  std::unique_ptr large_data{new char[rest_amount]};
  memset(large_data.get(), 'X', rest_amount);

  writer->AppendMem(large_data.get(), rest_amount);
}

TEST(GenericWriterTest, File) {
#ifndef _WIN32
  FILE* f = tmpfile();
  if (!f) {
    perror("tmpfile");
    abort();
  }

  {
    tcmalloc::RawFDGenericWriter<128> writer(static_cast(fileno(f)));
    PrintLargeAmount(&writer);
  }

  rewind(f);
  fseek(f, 0, SEEK_END);
  EXPECT_EQ(ftell(f), kLargeAmount);

  rewind(f);

  std::string s;
  s.resize(kLargeAmount);
  fread(&(s[0]), 1, kLargeAmount, f);

  EXPECT_EQ(s, expected_output);
#endif
}

TEST(GenericWriterTest, ChunkedWriting) {
  char* str = tcmalloc::WithWriterToStrDup(
    tcmalloc::ChunkedWriterConfig{malloc, free, 128},
    [] (GenericWriter* writer) {
      PrintLargeAmount(writer);
    });
  EXPECT_EQ(std::string(str), expected_output);
  free(str);
}

TEST(GenericWriterTest, String) {
  std::string s;
  {
    tcmalloc::StringGenericWriter writer(&s);
    PrintLargeAmount(&writer);
  }
  EXPECT_EQ(s, expected_output);
}
gperftools-gperftools-2.18/src/tests/getpc_test.cc000066400000000000000000000115321513545575200224310ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// This verifies that GetPC works correctly.  This test uses a minimum
// of Google infrastructure, to make it very easy to port to various
// O/Ses and CPUs and test that GetPC is working.

#include "config.h"
#include "getpc.h"        // should be first to get the _GNU_SOURCE dfn

#include "base/basictypes.h"

#include 
#include 
#include 
#include      // for setitimer

// Needs to be volatile so compiler doesn't try to optimize it away
static volatile void* getpc_retval;    // what GetPC returns
static volatile bool prof_handler_called;

extern "C" {
  // This helps us inspect codegen of GetPC function, just in case.
  ATTRIBUTE_NOINLINE
  void* DoGetPC(const ucontext_t* uc) {
    return GetPC(*uc);
  }
}

static void prof_handler(int sig, siginfo_t*, void* signal_ucontext) {
  if (!prof_handler_called)
    getpc_retval = DoGetPC(reinterpret_cast(signal_ucontext));
  prof_handler_called = true;  // only store the retval once
}

static void RoutineCallingTheSignal() {
  struct sigaction sa;
  sa.sa_sigaction = prof_handler;
  sa.sa_flags = SA_RESTART | SA_SIGINFO;
  sigemptyset(&sa.sa_mask);
  if (sigaction(SIGPROF, &sa, nullptr) != 0) {
    perror("sigaction");
    exit(1);
  }

  struct itimerval timer;
  timer.it_interval.tv_sec = 0;
  timer.it_interval.tv_usec = 1000;
  timer.it_value = timer.it_interval;
  setitimer(ITIMER_PROF, &timer, 0);

  // Now we need to do some work for a while, that doesn't call any
  // other functions, so we can be guaranteed that when the SIGPROF
  // fires, we're the routine executing.
  int r = 0;
  for (int i = 0; !prof_handler_called; ++i) {
    for (int j = 0; j < i; j++) {
      r ^= i;
      r <<= 1;
      r ^= j;
      r >>= 1;
    }
  }

  // Now make sure the above loop doesn't get optimized out
  srand(r);
}

// This is an upper bound of how many bytes the instructions for
// RoutineCallingTheSignal might be.  There's probably a more
// principled way to do this, but I don't know how portable it would be.
// (The function is 372 bytes when compiled with -g on Mac OS X 10.4.
// I can imagine it would be even bigger in 64-bit architectures.)
const int kRoutineSize = 512 * sizeof(void*)/4;    // allow 1024 for 64-bit

int main(int argc, char** argv) {
  RoutineCallingTheSignal();

  // Annoyingly, C++ disallows casting pointer-to-function to
  // pointer-to-object, so we use a C-style cast instead.
  char* expected = (char*)&RoutineCallingTheSignal;
  char* actual = (char*)getpc_retval;

  // For ia64, ppc64v1, and parisc64, the function pointer is actually
  // a struct.  For instance, ia64's dl-fptr.h:
  //   struct fdesc {          /* An FDESC is a function descriptor.  */
  //      ElfW(Addr) ip;      /* code entry point */
  //      ElfW(Addr) gp;      /* global pointer */
  //   };
  // We want the code entry point.
  // NOTE: ppc64 ELFv2 (Little Endian) does not have function pointers
#if defined(__ia64) || \
    (defined(__powerpc64__) && _CALL_ELF != 2)
  expected = ((char**)expected)[0];         // this is "ip"
#endif

  if (actual < expected || actual > expected + kRoutineSize) {
    printf("Test FAILED: actual PC: %p, expected PC: %p\n", actual, expected);
    return 1;
  } else {
    printf("PASS\n");
    return 0;
  }
}
gperftools-gperftools-2.18/src/tests/heap-checker-stub-test.cc000066400000000000000000000052541513545575200245430ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config.h"

#include "gperftools/heap-checker.h"

#include 

#include 

#if defined __has_attribute
#  if __has_attribute(noinline)
#    define ATTR_NOINLINE __attribute__ ((noinline))
#  endif
#endif

ATTR_NOINLINE void partial() {
  std::string str;
  for (int i = 0; i < 1024; i++) {
    str.append("-");
  }
  printf("the thing: '%.10s\n", str.c_str());

  static std::string* staticted = new std::string("something");
  printf("staticted: %s\n", staticted->c_str());

  {
    HeapLeakChecker::Disabler disabled;
    std::string* leaked2 = new std::string("leaked2");
    printf("leaked2 address: %p\n", leaked2);
    printf("leaked2: %s\n", leaked2->c_str());
  }

  std::string* leaked3 = new std::string("leaked3");
  printf("leaked3 address: %p\n", leaked3);
  HeapLeakChecker::IgnoreObject(leaked3);
  printf("leaked3: %s\n", leaked3->c_str());
}

int main() {
  HeapLeakChecker heap_checker("test_foo");
  printf("sizeof(HeapLeakChecker) = %zu\n", sizeof(heap_checker));
  partial();
  if (!heap_checker.NoLeaks()) assert(nullptr == "heap memory leak");
}
gperftools-gperftools-2.18/src/tests/heap-profiler_unittest.cc000066400000000000000000000125161513545575200247670ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// A small program that just exercises our heap profiler by allocating
// memory and letting the heap-profiler emit a profile.  We don't test
// threads (TODO).  By itself, this unittest tests that the heap-profiler
// doesn't crash on simple programs, but its output can be analyzed by
// another testing script to actually verify correctness.  See, eg,
// heap-profiler_unittest.sh.

#include "config_for_unittests.h"

#include 

#include 
#include 
#include                   // for mkdir()
#include                // for mkdir() on freebsd and os x
#ifdef HAVE_UNISTD_H
#include                  // for fork()
#endif
#include                // for wait()
#include 

#include "base/basictypes.h"
#include "base/logging.h"
#include "testing_portal.h"

static const int kMaxCount = 100000;
int* g_array[kMaxCount];              // an array of int-vectors

static const char* volatile marker;

static ATTRIBUTE_NOINLINE void Allocate(int start, int end, int size) {
  // NOTE: we're using this to prevent gcc 5 from merging otherwise
  // identical Allocate & Allocate2 functions.
  marker = "Allocate";
  for (int i = start; i < end; ++i) {
    if (i < kMaxCount)
      g_array[i] = new int[size];
  }
}

static ATTRIBUTE_NOINLINE void Allocate2(int start, int end, int size) {
  marker = "Allocate2";
  for (int i = start; i < end; ++i) {
    if (i < kMaxCount)
      g_array[i] = new int[size];
  }
}

static void Deallocate(int start, int end) {
  for (int i = start; i < end; ++i) {
    delete[] g_array[i];
    g_array[i] = 0;
  }
}

static void TestHeapProfilerStartStopIsRunning() {
  // If you run this with whole-program heap-profiling on, than
  // IsHeapProfilerRunning should return true.
  if (!IsHeapProfilerRunning()) {
    const char* tmpdir = getenv("TMPDIR");
    if (tmpdir == nullptr)
      tmpdir = "/tmp";
    mkdir(tmpdir, 0755);     // if necessary
    HeapProfilerStart((std::string(tmpdir) + "/start_stop").c_str());
    CHECK(IsHeapProfilerRunning());

    Allocate(0, 40, 100);
    Deallocate(0, 40);

    HeapProfilerStop();
    CHECK(!IsHeapProfilerRunning());
  }
}

static void TestDumpHeapProfiler() {
  // If you run this with whole-program heap-profiling on, than
  // IsHeapProfilerRunning should return true.
  if (!IsHeapProfilerRunning()) {
    const char* tmpdir = getenv("TMPDIR");
    if (tmpdir == nullptr)
      tmpdir = "/tmp";
    mkdir(tmpdir, 0755);     // if necessary
    HeapProfilerStart((std::string(tmpdir) + "/dump").c_str());
    CHECK(IsHeapProfilerRunning());

    Allocate(0, 40, 100);
    Deallocate(0, 40);

    char* output = GetHeapProfile();
    free(output);
    HeapProfilerStop();
  }
}


int main(int argc, char** argv) {
  tcmalloc::TestingPortal::Get()->GetSampleParameter() = 512 << 10;

  if (argc > 2 || (argc == 2 && argv[1][0] == '-')) {
    printf("USAGE: %s [number of children to fork]\n", argv[0]);
    exit(0);
  }
  int num_forks = 0;
  if (argc == 2) {
    num_forks = atoi(argv[1]);
  }

  TestHeapProfilerStartStopIsRunning();
  TestDumpHeapProfiler();

  Allocate(0, 40, 100);
  Deallocate(0, 40);

  Allocate(0, 40, 100);
  Allocate(0, 40, 100);
  Allocate2(40, 400, 1000);
  Allocate2(400, 1000, 10000);
  Deallocate(0, 1000);

  Allocate(0, 100, 100000);
  Deallocate(0, 10);
  Deallocate(10, 20);
  Deallocate(90, 100);
  Deallocate(20, 90);

  while (num_forks-- > 0) {
    switch (fork()) {
      case -1:
        printf("FORK failed!\n");
        return 1;
      case 0:             // child
        return execl(argv[0], argv[0], nullptr);   // run child with no args
      default:
        wait(nullptr);       // we'll let the kids run one at a time
    }
  }

  printf("DONE.\n");

  return 0;
}
gperftools-gperftools-2.18/src/tests/heap-profiler_unittest.sh000077500000000000000000000115211513545575200250120ustar00rootroot00000000000000#!/bin/sh

# Copyright (c) 2005, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# ---
# Author: Craig Silverstein
#
# Runs the heap-profiler unittest and makes sure the profile looks appropriate.
#

# This script runs either as heap-profiler_unittest.sh or as
# heap-profiler_debug_unittest.sh. And we want to run matching C
# program (i.e. linked to "normal" libtcmalloc or debug version).
DEFAULT_HEAP_PROFILER=`echo $0 | sed 's/.sh//'`
HEAP_PROFILER="${1:-$DEFAULT_HEAP_PROFILER}"
PPROF="pprof --hide=_tc_newarray"
TEST_TMPDIR=`mktemp -d /tmp/heap-profiler_unittest.XXXXXX`

# It's meaningful to the profiler, so make sure we know its state
unset HEAPPROFILE

num_failures=0

# Given one profile (to check the contents of that profile) or two
# profiles (to check the diff between the profiles), and a function
# name, verify that the function name takes up at least 90% of the
# allocated memory.  The function name is actually specified first.
VerifyMemFunction() {
  function="$1"
  shift

  if [ $# = 2 ]; then
    [ -f "$1" ] || { echo "Profile not found: $1"; exit 1; }
    [ -f "$2" ] || { echo "Profile not found: $2"; exit 1; }
    $PPROF --text --base="$1" "$2" >"$TEST_TMPDIR/output.pprof" 2>&1
  else
    [ -f "$1" ] || { echo "Profile not found: $1"; exit 1; }
    $PPROF --text "$1" >"$TEST_TMPDIR/output.pprof" 2>&1
  fi

  cat "$TEST_TMPDIR/output.pprof" \
      | tr -d % | awk '$6 ~ /^'$function'$/ && ($2+0) > 90 {exit 1;}'
  if [ $? != 1 ]; then
    echo
    echo "--- Test failed for $function: didn't account for 90% of executable memory"
    echo "--- Program output:"
    cat "$TEST_TMPDIR/output"
    echo "--- pprof output:"
    cat "$TEST_TMPDIR/output.pprof"
    echo "---"
    num_failures=`expr $num_failures + 1`
  fi
}

VerifyOutputContains() {
  text="$1"

  if ! grep "$text" "$TEST_TMPDIR/output" >/dev/null 2>&1; then
    echo "--- Test failed: output does not contain '$text'"
    echo "--- Program output:"
    cat "$TEST_TMPDIR/output"
    echo "---"
    num_failures=`expr $num_failures + 1`
  fi
}

HEAPPROFILE="$TEST_TMPDIR/test"
HEAP_PROFILE_INUSE_INTERVAL="10240"   # need this to be 10Kb
HEAP_PROFILE_ALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL"
HEAP_PROFILE_DEALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL"
export HEAPPROFILE
export HEAP_PROFILE_INUSE_INTERVAL
export HEAP_PROFILE_ALLOCATION_INTERVAL
export HEAP_PROFILE_DEALLOCATION_INTERVAL

# We make the unittest run a child process, to test that the child
# process doesn't try to write a heap profile as well and step on the
# parent's toes.  If it does, we expect the parent-test to fail.
$HEAP_PROFILER 1 >$TEST_TMPDIR/output 2>&1     # run program, with 1 child proc

VerifyMemFunction Allocate2 "$HEAPPROFILE.1329.heap"
VerifyMemFunction Allocate "$HEAPPROFILE.1448.heap" "$HEAPPROFILE.1548.heap"

# Check the child process got to emit its own profile as well.
VerifyMemFunction Allocate2 "$HEAPPROFILE"_*.1329.heap
VerifyMemFunction Allocate "$HEAPPROFILE"_*.1448.heap "$HEAPPROFILE"_*.1548.heap

# Make sure we logged both about allocating and deallocating memory
VerifyOutputContains "62 MB allocated"
VerifyOutputContains "62 MB freed"

# Now try running without --heap_profile specified, to allow
# testing of the HeapProfileStart/Stop functionality.
$HEAP_PROFILER >"$TEST_TMPDIR/output2" 2>&1

rm -rf $TEST_TMPDIR      # clean up

if [ $num_failures = 0 ]; then
  echo "PASS"
else
  echo "Tests finished with $num_failures failures"
fi
exit $num_failures
gperftools-gperftools-2.18/src/tests/large_heap_fragmentation_unittest.cc000066400000000000000000000061441513545575200272370ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// This is a unit test for exercising fragmentation of large (over 1
// meg) page spans. It makes sure that allocations/releases of
// increasing memory chunks do not blowup memory
// usage. See also https://github.com/gperftools/gperftools/issues/371
#include "config.h"

#include 
#include 

#include 
#include 
#include 

#include "gtest/gtest.h"

TEST(LargeHeapFragmentationTest, Basic) {
  // First grow heap by single large amount, to ensure that we do have
  // a big chunk of consecutive memory. Otherwise details of
  // sys-allocator behavior may trigger fragmentation regardless of
  // our mitigations.
#ifndef _WIN32
  static constexpr size_t kInitialAmt = 550 << 20;
#else
  // FIXME: on windows it is quite painful due to syscalls that we do
  // when returning memory to kernel whenever returned span touches
  // more than one memory "reservation" area. So for now, lets reduce
  // pain. And in the future lets make windows case fast.
  static constexpr size_t kInitialAmt = 1000 << 20;
#endif

  tc_free(tc_malloc(kInitialAmt));
  MallocExtension::instance()->ReleaseFreeMemory();

  for (int pass = 1; pass <= 3; pass++) {
    size_t size = 100*1024*1024;
    while (size < 500*1024*1024) {
      void *ptr = tc_malloc(size);
      free(ptr);
      size += 20000;

      size_t heap_size = static_cast(-1);
      ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty(
                    "generic.heap_size",
                    &heap_size));

      ASSERT_LT(heap_size, 1 << 30);
    }
  }
}
gperftools-gperftools-2.18/src/tests/low_level_alloc_unittest.cc000066400000000000000000000132311513545575200253670ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2006, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// A test for low_level_alloc.cc

#include "base/low_level_alloc.h"

#include 
#include 

#include "gtest/gtest.h"

using tcmalloc::LowLevelAlloc;

// a block of memory obtained from the allocator
struct BlockDesc {
  char *ptr;      // pointer to memory
  int len;        // number of bytes
  int fill;       // filled with data starting with this
};

// Check that the pattern placed in the block d
// by RandomizeBlockDesc is still there.
static void CheckBlockDesc(const BlockDesc &d) {
  for (int i = 0; i != d.len; i++) {
    ASSERT_TRUE((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff));
  }
}

// Fill the block "*d" with a pattern
// starting with a random byte.
static void RandomizeBlockDesc(BlockDesc *d) {
  d->fill = rand() & 0xff;
  for (int i = 0; i != d->len; i++) {
    d->ptr[i] = (d->fill + i) & 0xff;
  }
}

class TestPagesAllocator : public LowLevelAlloc::PagesAllocator {
public:
  struct TestHeader {
    static inline constexpr uint32_t kMagic = 0x74e5ca8;

    const uint32_t magic = kMagic;
    const size_t size;
    TestHeader(size_t size) : size(size) {}
  };

  uint64_t uses_count{};
  uint64_t in_use{};

  ~TestPagesAllocator() override = default;

  std::pair MapPages(size_t size) override {
    auto memory = (::operator new)(size + sizeof(TestHeader));
    TestHeader* hdr = new (memory) TestHeader(size);
    uses_count++;
    in_use += size;
    return {hdr + 1, size};
  }

  void UnMapPages(void *addr, size_t size) override {
    TestHeader* hdr = reinterpret_cast(addr) - 1;
    ASSERT_TRUE(hdr->size == size);
    ASSERT_TRUE(hdr->magic == TestHeader::kMagic);
    in_use -= size;
    (::operator delete)(hdr, size + sizeof(TestHeader));
  }
};

// n times, toss a coin, and based on the outcome
// either allocate a new block or deallocate an old block.
// New blocks are placed in a map with a random key
// and initialized with RandomizeBlockDesc().
// If keys conflict, the older block is freed.
// Old blocks are always checked with CheckBlockDesc()
// before being freed.  At the end of the run,
// all remaining allocated blocks are freed.
// If use_new_arena is true, use a fresh arena, and then delete it.
static void ExerciseAllocator(bool use_new_arena, int n) {
  typedef std::map AllocMap;
  AllocMap allocated;
  AllocMap::iterator it;
  BlockDesc block_desc;
  int rnd;
  LowLevelAlloc::Arena *arena = 0;

  TestPagesAllocator test_allocator;

  if (use_new_arena) {
    arena = LowLevelAlloc::NewArenaWithCustomAlloc(&test_allocator);
  }
  for (int i = 0; i != n; i++) {
    if (i != 0 && i % 10000 == 0) {
      printf(".");
      fflush(stdout);
    }

    switch(rand() & 1) {      // toss a coin
    case 0:     // coin came up heads: add a block
      block_desc.len = rand() & 0x3fff;
      block_desc.ptr =
        reinterpret_cast(
                        arena == 0
                        ? LowLevelAlloc::Alloc(block_desc.len)
                        : LowLevelAlloc::AllocWithArena(block_desc.len, arena));
      RandomizeBlockDesc(&block_desc);
      rnd = rand();
      it = allocated.find(rnd);
      if (it != allocated.end()) {
        CheckBlockDesc(it->second);
        LowLevelAlloc::Free(it->second.ptr);
        it->second = block_desc;
      } else {
        allocated[rnd] = block_desc;
      }
      break;
    case 1:     // coin came up tails: remove a block
      it = allocated.begin();
      if (it != allocated.end()) {
        CheckBlockDesc(it->second);
        LowLevelAlloc::Free(it->second.ptr);
        allocated.erase(it);
      }
      break;
    }
  }
  // remove all remaniing blocks
  while ((it = allocated.begin()) != allocated.end()) {
    CheckBlockDesc(it->second);
    LowLevelAlloc::Free(it->second.ptr);
    allocated.erase(it);
  }
  if (use_new_arena) {
    ASSERT_GT(test_allocator.uses_count, 0);
    ASSERT_GT(test_allocator.in_use, 0);
    ASSERT_TRUE(LowLevelAlloc::DeleteArena(arena));
    ASSERT_EQ(test_allocator.in_use, 0);
  }
}

TEST(LowLevelAllocTest, Basic) {
  ExerciseAllocator(false, 50000);
  for (int i = 0; i < 8; i++) {
    ExerciseAllocator(true, 15000);
  }
}
gperftools-gperftools-2.18/src/tests/malloc_extension_c_test.cc000066400000000000000000000101331513545575200251700ustar00rootroot00000000000000/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* Copyright (c) 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Craig Silverstein
 *
 * This tests the c shims: malloc_extension_c.h and malloc_hook_c.h.
 */

#include "config.h"

#include 
#include 
#include 

#include 
#include 
#include    /* for size_t */

#include "gtest/gtest.h"

static int g_new_hook_calls = 0;
static int g_delete_hook_calls = 0;

void TestNewHook(const void* ptr, size_t size) {
  void* result[5];

  ASSERT_LE(MallocHook_GetCallerStackTrace(
              result,
              sizeof(result)/sizeof(*result), 0),
            2);

  g_new_hook_calls++;
}

void TestDeleteHook(const void* ptr) {
  g_delete_hook_calls++;
}

static
void *forced_malloc(size_t size)
{
  void *rv = tc_malloc(size);
  if (!rv) {
    abort();
  }
  return rv;
}

TEST(TestMalloc, Hook) {
  ASSERT_TRUE(MallocHook_AddNewHook(&TestNewHook));
  ASSERT_TRUE(MallocHook_AddDeleteHook(&TestDeleteHook));

  free(forced_malloc(10));
  free(forced_malloc(20));
  ASSERT_EQ(g_new_hook_calls, 2);
  ASSERT_EQ(g_delete_hook_calls, 2);
  ASSERT_TRUE(MallocHook_RemoveNewHook(&TestNewHook));

  ASSERT_TRUE(MallocHook_RemoveDeleteHook(&TestDeleteHook));

  free(forced_malloc(10));
  free(forced_malloc(20));
  ASSERT_EQ(g_new_hook_calls, 2);

  MallocHook_SetNewHook(&TestNewHook);
  MallocHook_SetDeleteHook(&TestDeleteHook);

  free(forced_malloc(10));
  free(forced_malloc(20));
  ASSERT_EQ(g_new_hook_calls, 4);

  ASSERT_NE(MallocHook_SetNewHook(nullptr), nullptr);
  ASSERT_NE(MallocHook_SetDeleteHook(nullptr), nullptr);
}

TEST(TestMalloc, Extension) {
  int blocks;
  size_t total;
  int hist[64];
  char buffer[200];
  char* x = (char*)forced_malloc(10);

  MallocExtension_VerifyAllMemory();
  MallocExtension_VerifyMallocMemory(x);
  MallocExtension_MallocMemoryStats(&blocks, &total, hist);
  MallocExtension_GetStats(buffer, sizeof(buffer));

  ASSERT_TRUE(
    MallocExtension_GetNumericProperty(
      "generic.current_allocated_bytes",
      &total));

  ASSERT_GE(total, 10) << "GetNumericProperty had bad return for generic.current_allocated_bytes";

  MallocExtension_MarkThreadIdle();
  MallocExtension_MarkThreadBusy();
  MallocExtension_ReleaseToSystem(1);
  MallocExtension_ReleaseFreeMemory();

  ASSERT_GE(MallocExtension_GetEstimatedAllocatedSize(10), 10);

  ASSERT_GE(MallocExtension_GetAllocatedSize(x), 10);
  ASSERT_EQ(MallocExtension_GetOwnership(x), MallocExtension_kOwned);
  ASSERT_EQ(MallocExtension_GetOwnership(hist), MallocExtension_kNotOwned);

  free(x);
}
gperftools-gperftools-2.18/src/tests/malloc_extension_test.cc000066400000000000000000000101171513545575200246700ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// Simple test of malloc_extension.  Includes test of C shims.

#include "config_for_unittests.h"

#include 
#include 

#include 
#include 

#include "gtest/gtest.h"

TEST(MallocExtensionTest, Basics) {
  void* a = malloc(1000);

  size_t cxx_bytes_used, c_bytes_used;
  ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty(
      "generic.current_allocated_bytes", &cxx_bytes_used));
  ASSERT_TRUE(MallocExtension_GetNumericProperty(
      "generic.current_allocated_bytes", &c_bytes_used));
  ASSERT_GT(cxx_bytes_used, 1000);
  ASSERT_EQ(cxx_bytes_used, c_bytes_used);

  ASSERT_TRUE(MallocExtension::instance()->VerifyAllMemory());
  ASSERT_TRUE(MallocExtension_VerifyAllMemory());

  ASSERT_EQ(MallocExtension::kOwned,
            MallocExtension::instance()->GetOwnership(a));

  ASSERT_EQ(MallocExtension::kNotOwned,
            MallocExtension::instance()->GetOwnership(&cxx_bytes_used));
  ASSERT_EQ(MallocExtension::kNotOwned,
            MallocExtension::instance()->GetOwnership(nullptr));
  ASSERT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000);
  // This is just a sanity check.  If we allocated too much, tcmalloc is broken
  ASSERT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000);
  ASSERT_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000), 1000);

  for (int i = 0; i < 10; ++i) {
    void *p = malloc(i);
    ASSERT_GE(MallocExtension::instance()->GetAllocatedSize(p),
             MallocExtension::instance()->GetEstimatedAllocatedSize(i));
    free(p);
  }

  // Check the c-shim version too.
  ASSERT_EQ(MallocExtension_kOwned, MallocExtension_GetOwnership(a));
  ASSERT_EQ(MallocExtension_kNotOwned,
            MallocExtension_GetOwnership(&cxx_bytes_used));
  ASSERT_EQ(MallocExtension_kNotOwned, MallocExtension_GetOwnership(nullptr));
  ASSERT_GE(MallocExtension_GetAllocatedSize(a), 1000);
  ASSERT_LE(MallocExtension_GetAllocatedSize(a), 5000);
  ASSERT_GE(MallocExtension_GetEstimatedAllocatedSize(1000), 1000);

  free(a);

  // Verify that the .cc file and .h file have the same enum values.
  ASSERT_EQ(static_cast(MallocExtension::kUnknownOwnership),
            static_cast(MallocExtension_kUnknownOwnership));
  ASSERT_EQ(static_cast(MallocExtension::kOwned),
            static_cast(MallocExtension_kOwned));
  ASSERT_EQ(static_cast(MallocExtension::kNotOwned),
            static_cast(MallocExtension_kNotOwned));
}
gperftools-gperftools-2.18/src/tests/malloc_hook_test.cc000066400000000000000000000200271513545575200236150ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ----
// Author: llib@google.com (Bill Clarke)

#include "config_for_unittests.h"

#include 
#include "malloc_hook-inl.h"

#include 
#include 

#include 
#include 
#include 
#include 

#include "tests/testutil.h"

#include "gtest/gtest.h"

using base::internal::kHookListMaxValues;

// Since HookList is a template and is defined in malloc_hook.cc, we can only
// use an instantiation of it from malloc_hook.cc.  We then reinterpret those
// values as integers for testing.
typedef base::internal::HookList TestHookList;


const MallocHook::NewHook kTestValue = [] (const void* ptr, size_t size) {
  printf("kTestValue\n");
};
const MallocHook::NewHook kAnotherTestValue = [] (const void* ptr, size_t size) {
  printf("kAnotherTestValue\n");
};
const MallocHook::NewHook kThirdTestValue = [] (const void* ptr, size_t size) {
  printf("kThirdTestValue\n");
};

TEST(HookListTest, InitialValueExists) {
  TestHookList list{kTestValue};
  MallocHook::NewHook values[2] = {};
  EXPECT_EQ(1, list.Traverse(values, 2));
  EXPECT_EQ(kTestValue, values[0]);
  EXPECT_EQ(1, list.priv_end);
}

TEST(HookListTest, CanRemoveInitialValue) {
  TestHookList list{kTestValue};
  ASSERT_TRUE(list.Remove(kTestValue));
  EXPECT_EQ(0, list.priv_end);

  MallocHook::NewHook values[2] = {};
  EXPECT_EQ(0, list.Traverse(values, 2));
}

TEST(HookListTest, AddAppends) {
  TestHookList list{kTestValue};
  ASSERT_TRUE(list.Add(kAnotherTestValue));
  EXPECT_EQ(2, list.priv_end);

  MallocHook::NewHook values[2] = {};
  EXPECT_EQ(2, list.Traverse(values, 2));
  EXPECT_EQ(kTestValue, values[0]);
  EXPECT_EQ(kAnotherTestValue, values[1]);
}

TEST(HookListTest, RemoveWorksAndWillClearSize) {
  TestHookList list{kTestValue};
  ASSERT_TRUE(list.Add(kAnotherTestValue));

  ASSERT_TRUE(list.Remove(kTestValue));
  EXPECT_EQ(2, list.priv_end);

  MallocHook::NewHook values[2] = {};
  EXPECT_EQ(1, list.Traverse(values, 2));
  EXPECT_EQ(kAnotherTestValue, values[0]);

  ASSERT_TRUE(list.Remove(kAnotherTestValue));
  EXPECT_EQ(0, list.priv_end);
  EXPECT_EQ(0, list.Traverse(values, 2));
}

TEST(HookListTest, AddPrependsAfterRemove) {
  TestHookList list{kTestValue};
  ASSERT_TRUE(list.Add(kAnotherTestValue));

  ASSERT_TRUE(list.Remove(kTestValue));
  EXPECT_EQ(2, list.priv_end);

  ASSERT_TRUE(list.Add(kThirdTestValue));
  EXPECT_EQ(2, list.priv_end);

  MallocHook::NewHook values[3] = {};
  EXPECT_EQ(2, list.Traverse(values, 3));
  EXPECT_EQ(kThirdTestValue, values[0]);
  EXPECT_EQ(kAnotherTestValue, values[1]);
}

TEST(HookListTest, InvalidAddRejected) {
  TestHookList list{kTestValue};
  EXPECT_FALSE(list.Add(nullptr));

  MallocHook::NewHook values[2] = {};
  EXPECT_EQ(1, list.Traverse(values, 2));
  EXPECT_EQ(kTestValue, values[0]);
  EXPECT_EQ(1, list.priv_end);
}

TEST(HookListTest, FillUpTheList) {
  TestHookList list{kTestValue};
  intptr_t num_inserts = 0;
  while (list.Add(reinterpret_cast(++num_inserts))) {
    // empty
  }
  EXPECT_EQ(kHookListMaxValues, num_inserts);
  EXPECT_EQ(kHookListMaxValues, list.priv_end);

  MallocHook::NewHook values[kHookListMaxValues + 1];
  EXPECT_EQ(kHookListMaxValues, list.Traverse(values,
                                              kHookListMaxValues));
  EXPECT_EQ(kTestValue, values[0]);
  for (intptr_t i = 1; i < kHookListMaxValues; ++i) {
    EXPECT_EQ(reinterpret_cast(i), values[i]);
  }
}

void MultithreadedTestThread(TestHookList* list, int shift,
                             int thread_num) {
  std::string message;
  char buf[64];
  for (intptr_t i = 1; i < 1000; ++i) {
    // In each loop, we insert a unique value, check it exists, remove it, and
    // check it doesn't exist.  We also record some stats to log at the end of
    // each thread.  Each insertion location and the length of the list is
    // non-deterministic (except for the very first one, over all threads, and
    // after the very last one the list should be empty).
    const auto value = reinterpret_cast((i << shift) + thread_num);
    EXPECT_TRUE(list->Add(value));

    std::this_thread::yield();  // Ensure some more interleaving.

    MallocHook::NewHook values[kHookListMaxValues + 1];
    int num_values = list->Traverse(values, kHookListMaxValues + 1);
    EXPECT_LT(0, num_values);

    int value_index;
    for (value_index = 0;
         value_index < num_values && values[value_index] != value;
         ++value_index) {
      // empty
    }

    EXPECT_LT(value_index, num_values);  // Should have found value.
    snprintf(buf, sizeof(buf), "[%d/%d; ", value_index, num_values);
    message += buf;

    std::this_thread::yield();

    EXPECT_TRUE(list->Remove(value));

    std::this_thread::yield();

    num_values = list->Traverse(values, kHookListMaxValues);
    for (value_index = 0;
         value_index < num_values && values[value_index] != value;
         ++value_index) {
      // empty
    }

    EXPECT_EQ(value_index, num_values);  // Should not have found value.
    snprintf(buf, sizeof(buf), "%d]", num_values);
    message += buf;

    std::this_thread::yield();
  }
  fprintf(stderr, "thread %d: %s\n", thread_num, message.c_str());
}

static int num_threads_remaining;
static TestHookList list{kTestValue};
static std::mutex threadcount_lock;
static std::condition_variable threadcount_ready;

void MultithreadedTestThreadRunner(int thread_num) {
  // Wait for all threads to start running.
  {
    std::unique_lock ml{threadcount_lock};

    assert(num_threads_remaining > 0);
    --num_threads_remaining;

    threadcount_ready.wait(ml, [&] () { return num_threads_remaining == 0; });
    // the last thread to decrement to 0 will wake everyone
    threadcount_ready.notify_all();
  }

  // shift is the smallest number such that (1< kHookListMaxValues
  int shift = 0;
  for (int i = kHookListMaxValues; i > 0; i >>= 1) {
    shift += 1;
  }

  MultithreadedTestThread(&list, shift, thread_num);
}


TEST(HookListTest, MultithreadedTest) {
  ASSERT_TRUE(list.Remove(kTestValue));
  ASSERT_EQ(0, list.priv_end);

  // Run kHookListMaxValues thread, each running MultithreadedTestThread.
  // First, we need to set up the rest of the globals.
  num_threads_remaining = kHookListMaxValues;   // a global var
  RunManyThreadsWithId(&MultithreadedTestThreadRunner, num_threads_remaining);

  MallocHook::NewHook values[kHookListMaxValues + 1];
  EXPECT_EQ(0, list.Traverse(values, kHookListMaxValues + 1));
  EXPECT_EQ(0, list.priv_end);
}
gperftools-gperftools-2.18/src/tests/markidle_unittest.cc000066400000000000000000000072611513545575200240230ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2003, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// MallocExtension::MarkThreadIdle() testing
#include "config_for_unittests.h"

#include 

#include 

#include 
#include 

#include "gtest/gtest.h"

// Helper routine to do lots of allocations
static void TestAllocation() {
  static const int kNum = 100;
  void* ptr[kNum];
  for (int size = 8; size <= 65536; size*=2) {
    for (int i = 0; i < kNum; i++) {
      ptr[i] = ::operator new(size);
    }
    for (int i = 0; i < kNum; i++) {
      ::operator delete(ptr[i]);
    }
  }
}

// Routine that does a bunch of MarkThreadIdle() calls in sequence
// without any intervening allocations
TEST(MarkIdleTest, MultipleIdleCalls) {
  std::thread t([] () {
    for (int i = 0; i < 4; i++) {
      MallocExtension::instance()->MarkThreadIdle();
    }
  });

  t.join();
}

// Routine that does a bunch of MarkThreadIdle() calls in sequence
// with intervening allocations
TEST(MarkIdleTest, MultipleIdleNonIdlePhases) {
  std::thread t([] () {
    for (int i = 0; i < 4; i++) {
      TestAllocation();
      MallocExtension::instance()->MarkThreadIdle();
    }
  });

  t.join();
}

// Get current thread cache usage
static size_t GetTotalThreadCacheSize() {
  size_t result;
  EXPECT_TRUE(MallocExtension::instance()->GetNumericProperty(
                "tcmalloc.current_total_thread_cache_bytes",
                &result));
  return result;
}

// Check that MarkThreadIdle() actually reduces the amount
// of per-thread memory.
TEST(MarkIdleTest, TestIdleUsage) {
  std::thread t([] () {
    const size_t original = GetTotalThreadCacheSize();

    TestAllocation();
    const size_t post_allocation = GetTotalThreadCacheSize();
    EXPECT_GT(post_allocation, original);

    MallocExtension::instance()->MarkThreadIdle();
    const size_t post_idle = GetTotalThreadCacheSize();
    EXPECT_LE(post_idle, original);

    // Log after testing because logging can allocate heap memory.
    printf("Original usage: %zu\n", original);
    printf("Post allocation: %zu\n", post_allocation);
    printf("Post idle: %zu\n", post_idle);
  });

  t.join();
}
gperftools-gperftools-2.18/src/tests/memalign_unittest.cc000066400000000000000000000153071513545575200240240ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2004, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// Check memalign related routines.
//
// We can't really do a huge amount of checking, but at the very
// least, the following code checks that return values are properly
// aligned, and that writing into the objects works.

#include "config_for_unittests.h"

// Complicated ordering requirements.  tcmalloc.h defines (indirectly)
// _POSIX_C_SOURCE, which it needs so stdlib.h defines posix_memalign.
// unistd.h, on the other hand, requires _POSIX_C_SOURCE to be unset,
// at least on Mac OS X, in order to define getpagesize.  The solution
// is to #include unistd.h first.  This is safe because unistd.h
// doesn't sub-include stdlib.h, so we'll still get posix_memalign
// when we #include stdlib.h.  Blah.
#ifdef HAVE_UNISTD_H
#include             // for getpagesize()
#endif
#include "tcmalloc_internal.h" // must come early, to pick up posix_memalign
#include 
#include             // defines posix_memalign
#include              // for the printf at the end
#include             // for uintptr_t
#ifdef HAVE_UNISTD_H
#include             // for getpagesize()
#endif
// Malloc can be in several places on older versions of OS X.
#if defined(HAVE_MALLOC_H)
#include             // for memalign() and valloc()
#elif defined(HAVE_MALLOC_MALLOC_H)
#include 
#elif defined(HAVE_SYS_MALLOC_H)
#include 
#endif

#include "base/logging.h"

#include "tests/testutil.h"
#include "gtest/gtest.h"

// Return the next interesting size/delta to check.  Returns -1 if no more.
static int NextSize(int size) {
  if (size < 100) {
    return size+1;
  } else if (size < 1048576) {
    // Find next power of two
    int power = 1;
    while (power < size) {
      power <<= 1;
    }

    // Yield (power-1, power, power+1)
    if (size < power-1) {
      return power-1;
    } else if (size == power-1) {
      return power;
    } else {
      assert(size == power);
      return power+1;
    }
  } else {
    return -1;
  }
}

static uintptr_t Misallignment(void* p, size_t mask) {
  CHECK_NE(mask, 0);
  CHECK_EQ(mask & (mask-1), 0);
  return  reinterpret_cast(p) & uintptr_t{mask - 1};
}

// Fill a buffer of the specified size with a predetermined pattern
static void Fill(void* p, int n, char seed) {
  unsigned char* buffer = reinterpret_cast(p);
  for (int i = 0; i < n; i++) {
    buffer[i] = ((seed + i) & 0xff);
  }
}

// Check that the specified buffer has the predetermined pattern
// generated by Fill()
static bool Valid(const void* p, int n, char seed) {
  const unsigned char* buffer = reinterpret_cast(p);
  for (int i = 0; i < n; i++) {
    if (buffer[i] != ((seed + i) & 0xff)) {
      return false;
    }
  }
  return true;
}

// int main(int argc, char** argv) {
TEST(MemalignTest, Basic) {
  // Try allocating data with a bunch of alignments and sizes
  for (int a = 1; a < 1048576; a *= 2) {
    for (int s = 0; s != -1; s = NextSize(s)) {
      void* ptr = memalign(a, s);
      ASSERT_EQ(Misallignment(ptr, a), 0);
      Fill(ptr, s, 'x');
      CHECK(Valid(ptr, s, 'x'));
      free(ptr);

      if ((a >= sizeof(void*)) && ((a & (a-1)) == 0)) {
        CHECK(posix_memalign(&ptr, a, s) == 0);
        ASSERT_EQ(Misallignment(ptr, a), 0);
        Fill(ptr, s, 'y');
        CHECK(Valid(ptr, s, 'y'));
        free(ptr);
      }
    }
  }

  {
    // Check various corner cases
    void* p1 = memalign(1<<20, 1<<19);
    void* p2 = memalign(1<<19, 1<<19);
    void* p3 = memalign(1<<21, 1<<19);
    ASSERT_EQ(Misallignment(p1, 1<<20), 0);
    ASSERT_EQ(Misallignment(p2, 1<<19), 0);
    ASSERT_EQ(Misallignment(p3, 1<<21), 0);
    Fill(p1, 1<<19, 'a');
    Fill(p2, 1<<19, 'b');
    Fill(p3, 1<<19, 'c');
    CHECK(Valid(p1, 1<<19, 'a'));
    CHECK(Valid(p2, 1<<19, 'b'));
    CHECK(Valid(p3, 1<<19, 'c'));
    free(p1);
    free(p2);
    free(p3);
  }

  {
    // posix_memalign
    void* ptr;
    CHECK(posix_memalign(&ptr, 0, 1) == EINVAL);
    CHECK(posix_memalign(&ptr, sizeof(void*)/2, 1) == EINVAL);
    CHECK(posix_memalign(&ptr, sizeof(void*)+1, 1) == EINVAL);
    CHECK(posix_memalign(&ptr, 4097, 1) == EINVAL);

    // Grab some memory so that the big allocation below will definitely fail.
    void* p_small = noopt(malloc)(4*1048576);
    CHECK_NE(p_small, nullptr);

    // Make sure overflow is returned as ENOMEM
    const size_t zero = 0;
    constexpr size_t kMinusNTimes = 10;
    for ( size_t i = 1; i < kMinusNTimes; ++i ) {
      int r = posix_memalign(&ptr, 1024, zero - i);
      CHECK(r == ENOMEM);
    }

    free(p_small);
  }

  const int pagesize = getpagesize();
  {
    // valloc
    for (int s = 0; s != -1; s = NextSize(s)) {
      void* p = valloc(s);
      ASSERT_EQ(Misallignment(p, pagesize), 0);
      Fill(p, s, 'v');
      CHECK(Valid(p, s, 'v'));
      free(p);
    }
  }

  {
    // pvalloc
    for (int s = 0; s != -1; s = NextSize(s)) {
      void* p = pvalloc(s);
      ASSERT_EQ(Misallignment(p, pagesize), 0);
      int alloc_needed = ((s + pagesize - 1) / pagesize) * pagesize;
      Fill(p, alloc_needed, 'x');
      CHECK(Valid(p, alloc_needed, 'x'));
      free(p);
    }
  }
}
gperftools-gperftools-2.18/src/tests/min_per_thread_cache_size_test.cc000066400000000000000000000106051513545575200264640ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config_for_unittests.h"

#include 
#include 
#include 

#include 
#include 

#include "base/logging.h"
#include "gtest/gtest.h"

// Number of allocations per thread.
static const int kAllocationsPerThread = 10000;

// Number of threads to create.
static const int kNumThreads = 50;

// Per thread cache size to set.
static const size_t kPerThreadCacheSize = 64 << 10;

// Number of passes to run.
static const int kNumPasses = 10;

// Get current total thread-cache size.
static size_t CurrentThreadCacheSize() {
  size_t result = 0;
  EXPECT_TRUE(MallocExtension::instance()->GetNumericProperty(
                "tcmalloc.current_total_thread_cache_bytes",
                &result));
  return result;
}

// Maximum cache size seen so far.
static size_t max_cache_size;

// Mutex and condition variable to synchronize threads.
std::mutex filler_mtx;
std::condition_variable filler_cv;
int current_thread = 0;

// A thread that cycles through allocating lots of objects of varying
// size, in an attempt to fill up its thread cache.
void Filler(int thread_id, int num_threads) {
  std::unique_lock filler_lock(filler_mtx);
  for (int i = 0; i < kNumPasses; i++) {
    // Wait for the current thread to be the one that should run.
    filler_cv.wait(filler_lock, [thread_id] { return thread_id == current_thread; });

    // Fill the cache by allocating and deallocating objects of varying sizes.
    int size = 0;
    for (int i = 0; i < kAllocationsPerThread; i++) {
      void* p = ::operator new(size);
      ::operator delete(p);
      size += 64;
      if (size > (32 << 10)) size = 0;
    }

    // Get the maximum cache size seen so far.
    const size_t cache_size = CurrentThreadCacheSize();
    max_cache_size = std::max(max_cache_size, cache_size);

    // Move to the next thread.
    current_thread = (current_thread + 1) % num_threads;
    filler_cv.notify_all();
  }
}

TEST(MinPerThreadCacheSizeTest, Basics) {
  // Start all threads.
  std::vector threads;
  threads.reserve(kNumThreads);

  // Set the lower bound on per cache size.
  CHECK(MallocExtension::instance()->SetNumericProperty(
        "tcmalloc.min_per_thread_cache_bytes", kPerThreadCacheSize));

  // Setting the max total thread cache size to 0 to ensure that the
  // per thread cache size is set to the lower bound.
  CHECK(MallocExtension::instance()->SetNumericProperty(
        "tcmalloc.max_total_thread_cache_bytes", 0));

  for (int i = 0; i < kNumThreads; i++) {
    threads.emplace_back(Filler, i, kNumThreads);
  }

  // Wait for all threads to finish.
  for (auto& t : threads) { t.join(); }

  // Check that the maximum cache size does not exceed the limit set.
  ASSERT_LT(max_cache_size, kPerThreadCacheSize * kNumThreads);
}

gperftools-gperftools-2.18/src/tests/packed-cache_test.cc000066400000000000000000000053361513545575200236240ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Geoff Pike
#include "config_for_unittests.h"

#include "packed-cache-inl.h"

#include 

#include "gtest/gtest.h"

static constexpr int kHashbits = PackedCache<20>::kHashbits;

template 
static std::optional Get(const PackedCache& cache, uintptr_t key) {
  uint32_t rv;
  if (!cache.TryGet(key, &rv)) {
    return {};
  }
  return {rv};
}

template 
static size_t Has(const PackedCache& cache, uintptr_t key) {
  uint32_t dummy;
  return cache.TryGet(key, &dummy);
}

// A basic sanity test.
TEST(PackedCacheTest, Basic) {
  PackedCache<20> cache;

  ASSERT_FALSE(Has(cache, 0));
  cache.Put(0, 17);
  ASSERT_TRUE(Has(cache, 0));
  ASSERT_EQ(Get(cache, 0).value(), 17);

  cache.Put(19, 99);
  ASSERT_EQ(Get(cache, 0).value(), 17);
  ASSERT_EQ(Get(cache, 19).value(), 99);

  // Knock <0, 17> out by using a conflicting key.
  cache.Put(1 << kHashbits, 22);
  ASSERT_FALSE(Has(cache, 0));
  ASSERT_EQ(Get(cache, 1 << kHashbits).value(), 22);

  cache.Invalidate(19);
  ASSERT_FALSE(Has(cache, 19));
  ASSERT_FALSE(Has(cache, 0));
  ASSERT_TRUE(Has(cache, 1 << kHashbits));
}
gperftools-gperftools-2.18/src/tests/page_heap_test.cc000066400000000000000000000164241513545575200232450ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright 2009 Google Inc. All Rights Reserved.
// Author: fikes@google.com (Andrew Fikes)
//
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

#include "config_for_unittests.h"

#include 

#include 
#include 
#include 

#include "page_heap.h"

#include "base/cleanup.h"
#include "base/commandlineflags.h"
#include "system-alloc.h"

#include "gtest/gtest.h"

DECLARE_int64(tcmalloc_heap_limit_mb);

// TODO: add testing from >1 min_span_size setting.

bool HaveSystemRelease() {
  static bool have = ([] () {
    size_t actual;
    auto ptr = TCMalloc_SystemAlloc(kPageSize, &actual, 0);
    return TCMalloc_SystemRelease(ptr, actual);
  })();
  return have;
}

#if __linux__ || __APPLE__ || _WIN32 || __FreeBSD__ || __NetBSD__
TEST(PageHeapTest, HaveSystemRelease) {
  ASSERT_TRUE(HaveSystemRelease());
}
#endif

static void CheckStats(const tcmalloc::PageHeap* ph,
                       uint64_t system_pages,
                       uint64_t free_pages,
                       uint64_t unmapped_pages) {
  tcmalloc::PageHeap::Stats stats = ph->StatsLocked();

  if (!HaveSystemRelease()) {
    free_pages += unmapped_pages;
    unmapped_pages = 0;
  }

  EXPECT_EQ(system_pages, stats.system_bytes >> kPageShift);
  EXPECT_EQ(free_pages, stats.free_bytes >> kPageShift);
  EXPECT_EQ(unmapped_pages, stats.unmapped_bytes >> kPageShift);
}

TEST(PageHeapTest, Stats) {
  std::unique_ptr ph(new tcmalloc::PageHeap());

  // Empty page heap
  CheckStats(ph.get(), 0, 0, 0);

  // Allocate a span 's1'
  tcmalloc::Span* s1 = ph->New(256);
  CheckStats(ph.get(), 256, 0, 0);

  // Split span 's1' into 's1', 's2'.  Delete 's2'
  tcmalloc::Span* s2 = ph->SplitForTest(s1, 128);
  ph->Delete(s2);
  CheckStats(ph.get(), 256, 128, 0);

  // Unmap deleted span 's2'
  {
      SpinLockHolder l(ph->pageheap_lock());
      ph->ReleaseAtLeastNPages(1);
  }
  CheckStats(ph.get(), 256, 0, 128);

  // Delete span 's1'
  ph->Delete(s1);
  CheckStats(ph.get(), 256, 128, 128);
}

TEST(PageHeapTest, Decommit) {
  if (!HaveSystemRelease()) {
      return;
  }

  std::unique_ptr ph(new tcmalloc::PageHeap());

  constexpr size_t kNumPtrs = 10;
  constexpr size_t kBigAllocPages = kMaxPages * 2;

  // Ensure we have a chunk of sequential memory useful for the test below.
  {
    tcmalloc::Span* s = ph->New(kBigAllocPages * kNumPtrs * 2);
    ASSERT_NE(s, nullptr);
    ph->Delete(s);
  }

  std::vector used_spans;
  std::vector free_spans;
  for (size_t i = 0; i < kNumPtrs; ++i) {
    // interleave free_spans and used_spans to prevent free_spans from coalescing
    free_spans.push_back(ph->New(kBigAllocPages));
    used_spans.push_back(ph->New(kBigAllocPages));
  }

  for (auto span : free_spans) {
    ph->Delete(span);
  }

  for (size_t i = 0; i < 2 * kNumPtrs; ++i) {
    {
      SpinLockHolder l(ph->pageheap_lock());
      EXPECT_EQ(kBigAllocPages, ph->ReleaseAtLeastNPages(1));
    }

    tcmalloc::Span* new_span = ph->New(kBigAllocPages);
    ph->Delete(new_span);
  }

  {
    SpinLockHolder l(ph->pageheap_lock());
    EXPECT_EQ(kBigAllocPages, ph->ReleaseAtLeastNPages(1));
  }
  for (auto span : free_spans) {
    EXPECT_EQ(span->location, tcmalloc::Span::ON_RETURNED_FREELIST);
  }

  for (auto span : used_spans) {
    ph->Delete(span);
  }
}

// The number of kMaxPages-sized Spans we will allocate and free during the
// tests.
// We will also do twice this many kMaxPages/2-sized ones.
static constexpr int kNumberMaxPagesSpans = 10;

// Allocates all the last-level page tables we will need. Doing this before
// calculating the base heap usage is necessary, because otherwise if any of
// these are allocated during the main test it will throw the heap usage
// calculations off and cause the test to fail.
static void AllocateAllPageTables() {
  // Make a separate PageHeap from the main test so the test can start without
  // any pages in the lists.
  std::unique_ptr ph(new tcmalloc::PageHeap());
  tcmalloc::Span *spans[kNumberMaxPagesSpans * 2];
  for (int i = 0; i < kNumberMaxPagesSpans; ++i) {
    spans[i] = ph->New(kMaxPages);
    EXPECT_NE(spans[i], nullptr);
  }
  for (int i = 0; i < kNumberMaxPagesSpans; ++i) {
    ph->Delete(spans[i]);
  }
  for (int i = 0; i < kNumberMaxPagesSpans * 2; ++i) {
    spans[i] = ph->New(kMaxPages >> 1);
    EXPECT_NE(spans[i], nullptr);
  }
  for (int i = 0; i < kNumberMaxPagesSpans * 2; ++i) {
    ph->Delete(spans[i]);
  }
}

TEST(PageHeapTest, Limit) {
  AllocateAllPageTables();

  tcmalloc::Cleanup restore_heap_limit_flag{[] () {
    FLAGS_tcmalloc_heap_limit_mb = 0;
  }};

  std::unique_ptr ph(new tcmalloc::PageHeap());

  // Lets also test if huge number of pages is ooming properly
  {
    auto res = ph->New(std::numeric_limits::max());
    ASSERT_EQ(res, nullptr);
    ASSERT_EQ(errno, ENOMEM);
  }

  ASSERT_EQ(kMaxPages, 1 << (20 - kPageShift));

  // We do not know much is taken from the system for other purposes,
  // so we detect the proper limit:
  {
    FLAGS_tcmalloc_heap_limit_mb = 1;
    tcmalloc::Span* s = nullptr;
    while((s = ph->New(kMaxPages)) == nullptr) {
      FLAGS_tcmalloc_heap_limit_mb++;
    }
    FLAGS_tcmalloc_heap_limit_mb += kNumberMaxPagesSpans - 1;
    ph->Delete(s);
    // We are [10, 11) mb from the limit now.
  }

  // Test AllocLarge and GrowHeap first:
  {
    tcmalloc::Span * spans[kNumberMaxPagesSpans];
    for (int i=0; iNew(kMaxPages);
      EXPECT_NE(spans[i], nullptr);
    }
    EXPECT_EQ(ph->New(kMaxPages), nullptr);

    for (int i=0; iDelete(spans[i]);
    }

    tcmalloc::Span *defragmented =
        ph->New(kNumberMaxPagesSpans / 2 * kMaxPages);

    if (HaveSystemRelease()) {
      // EnsureLimit should release deleted normal spans
      EXPECT_NE(defragmented, nullptr);
      ph->PrepareAndDelete(defragmented, [&] () {
        EXPECT_TRUE(ph->CheckExpensive());
      });
    }
    else
    {
      EXPECT_EQ(defragmented, nullptr);
      EXPECT_TRUE(ph->CheckExpensive());
    }

    for (int i=1; iDelete(spans[i]);
    }
  }

  // Once again, testing small lists this time (twice smaller spans):
  {
    tcmalloc::Span * spans[kNumberMaxPagesSpans * 2];
    for (int i=0; iNew(kMaxPages >> 1);
      EXPECT_NE(spans[i], nullptr);
    }
    // one more half size allocation may be possible:
    tcmalloc::Span * lastHalf = ph->New(kMaxPages >> 1);
    EXPECT_EQ(ph->New(kMaxPages >> 1), nullptr);

    for (int i=0; iDelete(spans[i]);
    }

    for (Length len = kMaxPages >> 2;
         len < kNumberMaxPagesSpans / 2 * kMaxPages; len = len << 1) {
      if(len <= kMaxPages >> 1 || HaveSystemRelease()) {
        tcmalloc::Span *s = ph->New(len);
        EXPECT_NE(s, nullptr);
        ph->Delete(s);
      }
    }

    {
        SpinLockHolder l(ph->pageheap_lock());
        EXPECT_TRUE(ph->CheckExpensive());
    }

    for (int i=1; iDelete(spans[i]);
    }

    if (lastHalf != nullptr) {
      ph->Delete(lastHalf);
    }
  }
}
gperftools-gperftools-2.18/src/tests/pagemap_unittest.cc000066400000000000000000000125741513545575200236500ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2003, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
#include "config_for_unittests.h"

#include "pagemap.h"

#include 
#include 

#include 
#include 
#include 

#include "gtest/gtest.h"

// Note: we leak memory every time a map is constructed, so do not
// create too many maps.

// Test specified map type
template 
void TestMap(int limit, bool limit_is_below_the_overflow_boundary) {
  printf("Running test with %d iterations...\n", limit);

  { // Test sequential ensure/assignment
    Type map(malloc);
    for (intptr_t i = 0; i < static_cast(limit); i++) {
      map.Ensure(i, 1);
      map.set(i, (void*)(i+1));
      ASSERT_EQ(map.get(i), (void*)(i+1));
    }
    for (intptr_t i = 0; i < static_cast(limit); i++) {
      ASSERT_EQ(map.get(i), (void*)(i+1));
    }
  }

  { // Test bulk Ensure
    Type map(malloc);
    map.Ensure(0, limit);
    for (intptr_t i = 0; i < static_cast(limit); i++) {
      map.set(i, (void*)(i+1));
      ASSERT_EQ(map.get(i), (void*)(i+1));
    }
    for (intptr_t i = 0; i < static_cast(limit); i++) {
      ASSERT_EQ(map.get(i), (void*)(i+1));
    }
  }

  // Test that we correctly notice overflow
  {
    Type map(malloc);
    ASSERT_EQ(map.Ensure(limit, limit+1), limit_is_below_the_overflow_boundary);
  }

  { // Test randomized accesses
    std::vector elements;
    for (intptr_t i = 0; i < static_cast(limit); i++) elements.push_back(i);
    std::shuffle(elements.begin(), elements.end(), std::mt19937(42));

    Type map(malloc);
    for (intptr_t i = 0; i < static_cast(limit); i++) {
      map.Ensure(elements[i], 1);
      map.set(elements[i], (void*)(elements[i]+1));
      ASSERT_EQ(map.get(elements[i]), (void*)(elements[i]+1));
    }
    for (intptr_t i = 0; i < static_cast(limit); i++) {
      ASSERT_EQ(map.get(i), (void*)(i+1));
    }
  }
}

// REQUIRES: BITS==10, i.e., valid range is [0,1023].
// Representations for different types will end up being:
//    PageMap1: array[1024]
//    PageMap2: array[32][32]
//    PageMap3: array[16][16][4]
template 
void TestNext(const char* name) {
  printf("Running NextTest %s\n", name);
  Type map(malloc);
  char a, b, c, d, e;

  // When map is empty
  ASSERT_EQ(map.Next(0), nullptr);
  ASSERT_EQ(map.Next(5), nullptr);
  ASSERT_EQ(map.Next(1<<30), nullptr);

  // Add a single value
  map.Ensure(40, 1);
  map.set(40, &a);
  ASSERT_EQ(map.Next(0), &a);
  ASSERT_EQ(map.Next(39), &a);
  ASSERT_EQ(map.Next(40), &a);
  ASSERT_EQ(map.Next(41), nullptr);
  ASSERT_EQ(map.Next(1<<30), nullptr);

  // Add a few values
  map.Ensure(41, 1);
  map.Ensure(100, 3);
  map.set(41, &b);
  map.set(100, &c);
  map.set(101, &d);
  map.set(102, &e);
  ASSERT_EQ(map.Next(0), &a);
  ASSERT_EQ(map.Next(39), &a);
  ASSERT_EQ(map.Next(40), &a);
  ASSERT_EQ(map.Next(41), &b);
  ASSERT_EQ(map.Next(42), &c);
  ASSERT_EQ(map.Next(63), &c);
  ASSERT_EQ(map.Next(64), &c);
  ASSERT_EQ(map.Next(65), &c);
  ASSERT_EQ(map.Next(99), &c);
  ASSERT_EQ(map.Next(100), &c);
  ASSERT_EQ(map.Next(101), &d);
  ASSERT_EQ(map.Next(102), &e);
  ASSERT_EQ(map.Next(103), nullptr);
}

TEST(PageMapTest, Everything) {
  ASSERT_NO_FATAL_FAILURE(TestMap>(100, true));
  ASSERT_NO_FATAL_FAILURE(TestMap>(1 << 10, false));
  ASSERT_NO_FATAL_FAILURE(TestMap>(100, true));
  ASSERT_NO_FATAL_FAILURE(TestMap>(1 << 20, false));
  ASSERT_NO_FATAL_FAILURE(TestMap>(100, true));
  ASSERT_NO_FATAL_FAILURE(TestMap>(1 << 20, false));

  ASSERT_NO_FATAL_FAILURE(TestNext>("PageMap1"));
  ASSERT_NO_FATAL_FAILURE(TestNext>("PageMap2"));
  ASSERT_NO_FATAL_FAILURE(TestNext>("PageMap3"));
}
gperftools-gperftools-2.18/src/tests/proc_maps_iterator_test.cc000066400000000000000000000127301513545575200252240ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "config_for_unittests.h"

#include "base/proc_maps_iterator.h"

#include 

#include 

#include "base/generic_writer.h"
#include "gtest/gtest.h"

#if defined __ELF__
#include 
#define PRINT_DL_PHDRS
#endif

int variable = 42; // initializing this puts this into .data section

// There is not much we can thoroughly test. But it is easy to test
// that we're seeing at least .data bits. We can also check that we saw
// at least one executable mapping.
TEST(ProcMapsIteratorTest, ForEachMapping) {
  bool seen_variable = false;
  bool seen_executable = false;
  bool ok = tcmalloc::ForEachProcMapping([&] (const tcmalloc::ProcMapping& mapping) {
    const uintptr_t variable_addr = reinterpret_cast(&variable);
    if (mapping.start <= variable_addr && variable_addr <= mapping.end) {
      seen_variable = true;
    }
    if (std::string(mapping.flags).find_first_of('x') != std::string::npos) {
      seen_executable = true;
    }
  });
  ASSERT_TRUE(ok) << "failed to open proc/self/maps";
  ASSERT_TRUE(seen_variable);
  ASSERT_TRUE(seen_executable);
}

#ifdef PRINT_DL_PHDRS

std::string MapFlags(uintptr_t flags) {
  std::string ret;
  ret += (flags & PF_R) ? "r" : "-";
  ret += (flags & PF_W) ? "w" : "-";
  ret += (flags & PF_X) ? "x" : "-";
  if ((flags & ~uintptr_t{PF_R | PF_W | PF_X})) {
    ret += " + junk";
  }
  return ret;
}

std::string MapType(uintptr_t p_type) {
#define PT(c) do { if (p_type == c) return (#c); } while (false)
#ifdef PT_NULL
  PT(PT_NULL);
#endif
#ifdef PT_LOAD
  PT(PT_LOAD);
#endif
#ifdef PT_DYNAMIC
  PT(PT_DYNAMIC);
#endif
#ifdef PT_INTERP
  PT(PT_INTERP);
#endif
#ifdef PT_NOTE
  PT(PT_NOTE);
#endif
#ifdef PT_SHLIB
  PT(PT_SHLIB);
#endif
#ifdef PT_PHDR
  PT(PT_PHDR);
#endif
#ifdef PT_TLS
  PT(PT_TLS);
#endif
#ifdef PT_NUM
  PT(PT_NUM);
#endif
#ifdef PT_LOOS
  PT(PT_LOOS);
#endif
#ifdef PT_GNU_EH_FRAME
  PT(PT_GNU_EH_FRAME);
#endif
#ifdef PT_GNU_STACK
  PT(PT_GNU_STACK);
#endif
#ifdef PT_GNU_RELRO
  PT(PT_GNU_RELRO);
#endif
#ifdef PT_GNU_PROPERTY
  PT(PT_GNU_PROPERTY);
#endif
#ifdef PT_GNU_SFRAME
  PT(PT_GNU_SFRAME);
#endif
#ifdef PT_LOSUNW
  PT(PT_LOSUNW);
#endif
#ifdef PT_SUNWBSS
  PT(PT_SUNWBSS);
#endif
#ifdef PT_SUNWSTACK
  PT(PT_SUNWSTACK);
#endif
#ifdef PT_HISUNW
  PT(PT_HISUNW);
#endif
#ifdef PT_HIOS
  PT(PT_HIOS);
#endif
#ifdef PT_LOPROC
  PT(PT_LOPROC);
#endif
#ifdef PT_HIPROC
  PT(PT_HIPROC);
#endif
#undef PT
  return "(UNKNOWN)";
}

void DoPrintPHDRs() {
  printf("iterating phdrs:\n");
  int rv = dl_iterate_phdr([] (struct dl_phdr_info *info, size_t _size, void* _bogus) -> int {
    printf("Got info. at = %p, path = '%s', num_phdrs = %d\n",
           reinterpret_cast(static_cast(info->dlpi_addr)),
           info->dlpi_name,
           (int)info->dlpi_phnum);
    for (int i = 0; i < info->dlpi_phnum; i++) {
      printf(" phdr %d: type = 0x%zx (%s), offset = 0x%zx, vaddr = 0x%zx - 0x%zx, filesz = %zu, memsz = %zu, flags = 0x%zx (%s), align = 0x%zx\n",
             i,
             (uintptr_t)info->dlpi_phdr[i].p_type, MapType(info->dlpi_phdr[i].p_type).c_str(),
             (uintptr_t)info->dlpi_phdr[i].p_offset,
             (uintptr_t)info->dlpi_phdr[i].p_vaddr, (uintptr_t)info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz,
             (uintptr_t)info->dlpi_phdr[i].p_filesz,
             (uintptr_t)info->dlpi_phdr[i].p_memsz,
             (uintptr_t)info->dlpi_phdr[i].p_flags, MapFlags(info->dlpi_phdr[i].p_flags).c_str(),
             (uintptr_t)info->dlpi_phdr[i].p_align);
    }
    return 0;
  }, nullptr);
  printf("dl_iterate rv = %d\n", rv);
}

#else
void DoPrintPHDRs() {}
#endif

TEST(ProcMapsIteratorTest, SaveMappingNonEmpty) {
  std::string s;
  {
    tcmalloc::StringGenericWriter writer(&s);
    tcmalloc::SaveProcSelfMaps(&writer);
  }
  // Lets at least ensure we got something
  ASSERT_NE(s.size(), 0);
  printf("Got the following:\n%s\n---\n", s.c_str());

  DoPrintPHDRs();
}
gperftools-gperftools-2.18/src/tests/profile-handler_unittest.cc000066400000000000000000000321561513545575200253070ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright 2009 Google Inc. All Rights Reserved.
// Author: Nabeel Mian (nabeelmian@google.com)
//         Chris Demetriou (cgd@google.com)
//
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
//
//
// This file contains the unit tests for profile-handler.h interface.

#include "config_for_unittests.h"

#include "profile-handler.h"

#include 
#include 
#include 
#include 
#include 

#include 
#include 

#include "base/logging.h"
#include "gtest/gtest.h"

// In order to cover fix for github issue at:
// https://github.com/gperftools/gperftools/issues/412 we override
// operators new/delete to simulate condition where another thread is
// having malloc lock and making sure that profiler handler can
// unregister callbacks without deadlocking. Thus this
// "infrastructure" below.
namespace {
std::atomic allocate_count;
std::atomic free_count;
// We also "frob" this lock down in BusyThread.
std::mutex allocate_lock;

void* do_allocate(size_t sz) {
  std::lock_guard l{allocate_lock};

  allocate_count++;
  return malloc(sz);
}
void do_free(void* p) {
  std::lock_guard l{allocate_lock};

  free_count++;
  free(p);
}
}  // namespace

void* operator new(size_t sz) { return do_allocate(sz); }
void* operator new[](size_t sz) { return do_allocate(sz); }
void operator delete(void* p) noexcept { do_free(p); }
void operator delete[](void* p) noexcept { do_free(p); }

void operator delete(void* p, size_t sz) noexcept { do_free(p); }
void operator delete[](void* p, size_t sz) noexcept { do_free(p); }

void* operator new(size_t sz, const std::nothrow_t& nt) noexcept { return do_allocate(sz); }
void* operator new[](size_t sz, const std::nothrow_t& nt) noexcept { return do_allocate(sz); };

void operator delete(void* p, const std::nothrow_t& nt) noexcept { do_free(p); }
void operator delete[](void* p, const std::nothrow_t& nt) noexcept { do_free(p); }

namespace {

// TODO(csilvers): error-checking on the pthreads routines
class Thread {
 public:
  Thread() : joinable_(false) { }
  virtual ~Thread() { }
  void SetJoinable(bool value) { joinable_ = value; }
  void Start() {
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_create(&thread_, &attr, &DoRun, this);
    pthread_attr_destroy(&attr);
  }
  void Join()  {
    assert(joinable_);
    pthread_join(thread_, nullptr);
  }
  virtual void Run() = 0;
 private:
  static void* DoRun(void* cls) {
    Thread* self = static_cast(cls);
    if (!self->joinable_) {
      CHECK_EQ(0, pthread_detach(pthread_self()));
    }

    ProfileHandlerRegisterThread();
    self->Run();
    return nullptr;
  }
  pthread_t thread_;
  bool joinable_;
};

// Sleep interval in nano secs. ITIMER_PROF goes off only afer the specified CPU
// time is consumed. Under heavy load this process may no get scheduled in a
// timely fashion. Therefore, give enough time (20x of ProfileHandle timer
// interval 10ms (100Hz)) for this process to accumulate enought CPU time to get
// a profile tick.
int kSleepInterval = 200000000;

// Sleep interval in nano secs. To ensure that if the timer has expired it is
// reset.
int kTimerResetInterval = 5000000;

static bool linux_per_thread_timers_mode_ = false;
static int timer_type_ = ITIMER_PROF;

// Delays processing by the specified number of nano seconds. 'delay_ns'
// must be less than the number of nano seconds in a second (1000000000).
void Delay(int delay_ns) {
  static const int kNumNSecInSecond = 1000000000;
  EXPECT_LT(delay_ns, kNumNSecInSecond);
  struct timespec delay = { 0, delay_ns };
  nanosleep(&delay, 0);
}

// Checks whether the profile timer is enabled for the current thread.
bool IsTimerEnabled() {
  itimerval current_timer;
  EXPECT_EQ(0, getitimer(timer_type_, ¤t_timer));
  return (current_timer.it_interval.tv_sec != 0 ||
          current_timer.it_interval.tv_usec != 0);
}

// Dummy worker thread to accumulate cpu time.
class BusyThread : public Thread {
 public:
  BusyThread() : stop_work_(false) {
  }

  // Setter/Getters
  bool stop_work() {
    std::lock_guard l{mu_};
    return stop_work_;
  }
  void set_stop_work(bool stop_work) {
    std::lock_guard l{mu_};
    stop_work_ = stop_work;
  }

 private:
  // Protects stop_work_ below.
  std::mutex mu_;
  // Whether to stop work?
  bool stop_work_;

  // Do work until asked to stop. We also stump on allocate_lock to
  // verify that perf handler re/unre-gistration doesn't deadlock with
  // malloc locks.
  void Run() {
    for (;;) {
      std::lock_guard l{allocate_lock};

      for (int i = 1000; i > 0; i--) {
        if (stop_work()) {
          return;
        }
        (void)*(const_cast(&stop_work_));
      }
    }
  }
};

class NullThread : public Thread {
 private:
  void Run() {
  }
};

// Signal handler which tracks the profile timer ticks.
static void TickCounter(int sig, siginfo_t* sig_info, void *vuc,
                        void* tick_counter) {
  int* counter = static_cast(tick_counter);
  ++(*counter);
}

// This class tests the profile-handler.h interface.
class ProfileHandlerTest : public ::testing::Test {
 protected:

  // Determines the timer type.
  static void SetUpTestCase() {
    timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);

#if HAVE_LINUX_SIGEV_THREAD_ID
    linux_per_thread_timers_mode_ = (getenv("CPUPROFILE_PER_THREAD_TIMERS") != nullptr);
    const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");
    if (signal_number) {
      //signal_number_ = strtol(signal_number, nullptr, 0);
      linux_per_thread_timers_mode_ = true;
      Delay(kTimerResetInterval);
    }
#endif
  }

  // Sets up the profile timers and SIGPROF/SIGALRM handler in a known state.
  // It does the following:
  // 1. Unregisters all the callbacks, stops the timer and clears out
  //    timer_sharing state in the ProfileHandler. This clears out any state
  //    left behind by the previous test or during module initialization when
  //    the test program was started.
  // 3. Starts a busy worker thread to accumulate CPU usage.
  void SetUp() override {
    // Reset the state of ProfileHandler between each test. This unregisters
    // all callbacks and stops the timer.
    ProfileHandlerReset();
    EXPECT_EQ(0, GetCallbackCount());
    VerifyDisabled();
    // Start worker to accumulate cpu usage.
    StartWorker();
  }

  void TearDown() override {
    ProfileHandlerReset();
    // Stops the worker thread.
    StopWorker();
  }

  // Starts a busy worker thread to accumulate cpu time. There should be only
  // one busy worker running. This is required for the case where there are
  // separate timers for each thread.
  void StartWorker() {
    busy_worker_ = new BusyThread();
    busy_worker_->SetJoinable(true);
    busy_worker_->Start();
    // Wait for worker to start up and register with the ProfileHandler.
    // TODO(nabeelmian) This may not work under very heavy load.
    Delay(kSleepInterval);
  }

  // Stops the worker thread.
  void StopWorker() {
    busy_worker_->set_stop_work(true);
    busy_worker_->Join();
    delete busy_worker_;
  }

  // Gets the number of callbacks registered with the ProfileHandler.
  uint32_t GetCallbackCount() {
    ProfileHandlerState state;
    ProfileHandlerGetState(&state);
    return state.callback_count;
  }

  // Gets the current ProfileHandler interrupt count.
  uint64_t GetInterruptCount() {
    ProfileHandlerState state;
    ProfileHandlerGetState(&state);
    return state.interrupts;
  }

  // Verifies that a callback is correctly registered and receiving
  // profile ticks.
  void VerifyRegistration(const int& tick_counter) {
    // Check the callback count.
    EXPECT_GT(GetCallbackCount(), 0);
    // Check that the profile timer is enabled.
    EXPECT_TRUE(linux_per_thread_timers_mode_ || IsTimerEnabled());
    uint64_t interrupts_before = GetInterruptCount();
    // Sleep for a bit and check that tick counter is making progress.
    int old_tick_count = tick_counter;
    int new_tick_count;
    uint64_t interrupts_after;
    Delay(kSleepInterval);

    // The "sleep" check we do here is somewhat inherently
    // brittle. But we can repeat waiting a bit more to ensure that
    // ticks do occur.
    for (int i = 10; i > 0; i--) {
      new_tick_count = tick_counter;
      interrupts_after = GetInterruptCount();
      if (new_tick_count > old_tick_count && interrupts_after > interrupts_before) {
        break;
      }
      Delay(kSleepInterval);
    }
    EXPECT_GT(new_tick_count, old_tick_count);
    EXPECT_GT(interrupts_after, interrupts_before);
  }

  // Verifies that a callback is not receiving profile ticks.
  void VerifyUnregistration(const int& tick_counter) {
    // Sleep for a bit and check that tick counter is not making progress.
    int old_tick_count = tick_counter;
    Delay(kSleepInterval);
    int new_tick_count = tick_counter;
    EXPECT_EQ(old_tick_count, new_tick_count);
    // If no callbacks, timer should be disabled.
    if (GetCallbackCount() == 0) {
      EXPECT_FALSE(IsTimerEnabled());
    }
  }

  // Verifies that the timer is disabled. Expects the worker to be running.
  void VerifyDisabled() {
    // Check that the callback count is 0.
    EXPECT_EQ(0, GetCallbackCount());
    // Check that the timer is disabled.
    EXPECT_FALSE(IsTimerEnabled());
    // Verify that the ProfileHandler is not accumulating profile ticks.
    uint64_t interrupts_before = GetInterruptCount();
    Delay(kSleepInterval);
    uint64_t interrupts_after = GetInterruptCount();
    EXPECT_EQ(interrupts_before, interrupts_after);
  }

  // Registers a callback and waits for kTimerResetInterval for timers to get
  // reset.
  ProfileHandlerToken* RegisterCallback(void* callback_arg) {
    ProfileHandlerToken* token = ProfileHandlerRegisterCallback(
        TickCounter, callback_arg);
    Delay(kTimerResetInterval);
    return token;
  }

  // Unregisters a callback and waits for kTimerResetInterval for timers to get
  // reset.
  void UnregisterCallback(ProfileHandlerToken* token) {
    allocate_count.store(0);
    free_count.store(0);
    ProfileHandlerUnregisterCallback(token);
    Delay(kTimerResetInterval);
    CHECK(free_count.load() > 0);
  }

  // Busy worker thread to accumulate cpu usage.
  BusyThread* busy_worker_;
};

// Verifies ProfileHandlerRegisterCallback and
// ProfileHandlerUnregisterCallback.
TEST_F(ProfileHandlerTest, RegisterUnregisterCallback) {
  int tick_count = 0;
  ProfileHandlerToken* token = RegisterCallback(&tick_count);
  VerifyRegistration(tick_count);
  UnregisterCallback(token);
  VerifyUnregistration(tick_count);
}

// Verifies that multiple callbacks can be registered.
TEST_F(ProfileHandlerTest, MultipleCallbacks) {
  // Register first callback.
  int first_tick_count = 0;
  ProfileHandlerToken* token1 = RegisterCallback(&first_tick_count);
  // Check that callback was registered correctly.
  VerifyRegistration(first_tick_count);
  EXPECT_EQ(1, GetCallbackCount());

  // Register second callback.
  int second_tick_count = 0;
  ProfileHandlerToken* token2 = RegisterCallback(&second_tick_count);
  // Check that callback was registered correctly.
  VerifyRegistration(second_tick_count);
  EXPECT_EQ(2, GetCallbackCount());

  // Unregister first callback.
  UnregisterCallback(token1);
  VerifyUnregistration(first_tick_count);
  EXPECT_EQ(1, GetCallbackCount());
  // Verify that second callback is still registered.
  VerifyRegistration(second_tick_count);

  // Unregister second callback.
  UnregisterCallback(token2);
  VerifyUnregistration(second_tick_count);
  EXPECT_EQ(0, GetCallbackCount());

  // Verify that the timers is correctly disabled.
  if (!linux_per_thread_timers_mode_) VerifyDisabled();
}

// Verifies ProfileHandlerReset
TEST_F(ProfileHandlerTest, Reset) {
  // Verify that the profile timer interrupt is disabled.
  if (!linux_per_thread_timers_mode_) VerifyDisabled();
  int first_tick_count = 0;
  RegisterCallback(&first_tick_count);
  VerifyRegistration(first_tick_count);
  EXPECT_EQ(1, GetCallbackCount());

  // Register second callback.
  int second_tick_count = 0;
  RegisterCallback(&second_tick_count);
  VerifyRegistration(second_tick_count);
  EXPECT_EQ(2, GetCallbackCount());

  // Reset the profile handler and verify that callback were correctly
  // unregistered and the timer is disabled.
  ProfileHandlerReset();
  VerifyUnregistration(first_tick_count);
  VerifyUnregistration(second_tick_count);
  if (!linux_per_thread_timers_mode_) VerifyDisabled();
}

// Verifies that ProfileHandler correctly handles a case where a callback was
// registered before the second thread started.
TEST_F(ProfileHandlerTest, RegisterCallbackBeforeThread) {
  // Stop the worker.
  StopWorker();
  // Unregister all existing callbacks and stop the timer.
  ProfileHandlerReset();
  EXPECT_EQ(0, GetCallbackCount());
  VerifyDisabled();

  // Start the worker.
  StartWorker();
  // Register a callback and check that profile ticks are being delivered and
  // the timer is enabled.
  int tick_count = 0;
  RegisterCallback(&tick_count);
  EXPECT_EQ(1, GetCallbackCount());
  VerifyRegistration(tick_count);
  EXPECT_TRUE(linux_per_thread_timers_mode_ || IsTimerEnabled());
}

}  // namespace
gperftools-gperftools-2.18/src/tests/profiledata_unittest.cc000066400000000000000000000451351513545575200245270ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Chris Demetriou
//
// This file contains the unit tests for the ProfileData class.

#include              // to get uintptr_t
#include 
#include 
#include 
#include 
#include 

#include "profiledata.h"

#include "base/logging.h"

#include "gtest/gtest.h"

namespace {

template class scoped_array {
 public:
  scoped_array(T* data) : data_(data) { }
  ~scoped_array() { delete[] data_; }
  T* get() { return data_; }
  T& operator[](int i) { return data_[i]; }
 private:
  T* const data_;
};

// Re-runs fn until it doesn't cause EINTR.
#define NO_INTR(fn)   do {} while ((fn) < 0 && errno == EINTR)

// Read up to "count" bytes from file descriptor "fd" into the buffer
// starting at "buf" while handling short reads and EINTR.  On
// success, return the number of bytes read.  Otherwise, return -1.
static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
  CHECK_GE(fd, 0);
  char *buf0 = reinterpret_cast(buf);
  ssize_t num_bytes = 0;
  while (num_bytes < count) {
    ssize_t len;
    NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
    if (len < 0) {  // There was an error other than EINTR.
      return -1;
    }
    if (len == 0) {  // Reached EOF.
      break;
    }
    num_bytes += len;
  }
  CHECK(num_bytes <= count);
  return num_bytes;
}

// Thin wrapper around a file descriptor so that the file descriptor
// gets closed for sure.
struct FileDescriptor {
  const int fd_;
  explicit FileDescriptor(int fd) : fd_(fd) {}
  ~FileDescriptor() {
    if (fd_ >= 0) {
      close(fd_);
    }
  }
  int get() { return fd_; }
};

// must be the same as with ProfileData::Slot.
typedef uintptr_t ProfileDataSlot;

// Quick and dirty function to make a number into a void* for use in a
// sample.
inline void* V(intptr_t x) { return reinterpret_cast(x); }

// String returned by ProfileDataChecker helper functions to indicate success.
const char kNoError[] = "";

class ProfileDataChecker {
 public:
  ProfileDataChecker() {
    const char* tmpdir = getenv("TMPDIR");
    if (tmpdir == nullptr)
      tmpdir = "/tmp";
    mkdir(tmpdir, 0755);     // if necessary
    filename_ = std::string(tmpdir) + "/profiledata_unittest.tmp";
  }

  std::string filename() const { return filename_; }

  // Checks the first 'num_slots' profile data slots in the file
  // against the data pointed to by 'slots'.  Returns kNoError if the
  // data matched, otherwise returns an indication of the cause of the
  // mismatch.
  std::string Check(const ProfileDataSlot* slots, int num_slots) {
    return CheckWithSkips(slots, num_slots, nullptr, 0);
  }

  // Checks the first 'num_slots' profile data slots in the file
  // against the data pointed to by 'slots', skipping over entries
  // described by 'skips' and 'num_skips'.
  //
  // 'skips' must be a sorted list of (0-based) slot numbers to be
  // skipped, of length 'num_skips'.  Note that 'num_slots' includes
  // any skipped slots, i.e., the first 'num_slots' profile data slots
  // will be considered, but some may be skipped.
  //
  // Returns kNoError if the data matched, otherwise returns an
  // indication of the cause of the mismatch.
  std::string CheckWithSkips(const ProfileDataSlot* slots, int num_slots,
                             const int* skips, int num_skips);

  // Validate that a profile is correctly formed.  The profile is
  // assumed to have been created by the same kind of binary (e.g.,
  // same slot size, same endian, etc.) as is validating the profile.
  //
  // Returns kNoError if the profile appears valid, otherwise returns
  // an indication of the problem with the profile.
  std::string ValidateProfile();

 private:
  std::string filename_;
};

std::string ProfileDataChecker::CheckWithSkips(const ProfileDataSlot* slots,
                                               int num_slots, const int* skips,
                                               int num_skips) {
  FileDescriptor fd(open(filename_.c_str(), O_RDONLY));
  if (fd.get() < 0)
    return "file open error";

  scoped_array filedata(new ProfileDataSlot[num_slots]);
  size_t expected_bytes = num_slots * sizeof filedata[0];
  ssize_t bytes_read = ReadPersistent(fd.get(), filedata.get(), expected_bytes);
  if (expected_bytes != bytes_read)
    return "file too small";

  for (int i = 0; i < num_slots; i++) {
    if (num_skips > 0 && *skips == i) {
      num_skips--;
      skips++;
      continue;
    }
    if (slots[i] != filedata[i])
      return "data mismatch";
  }
  return kNoError;
}

std::string ProfileDataChecker::ValidateProfile() {
  FileDescriptor fd(open(filename_.c_str(), O_RDONLY));
  if (fd.get() < 0)
    return "file open error";

  struct stat statbuf;
  if (fstat(fd.get(), &statbuf) != 0)
    return "fstat error";
  if (statbuf.st_size != static_cast(statbuf.st_size))
    return "file impossibly large";
  ssize_t filesize = statbuf.st_size;

  scoped_array filedata(new char[filesize]);
  if (ReadPersistent(fd.get(), filedata.get(), filesize) != filesize)
    return "read of whole file failed";

  // Must have enough data for the header and the trailer.
  if (filesize < (5 + 3) * sizeof(ProfileDataSlot))
    return "not enough data in profile for header + trailer";

  // Check the header
  if (reinterpret_cast(filedata.get())[0] != 0)
    return "error in header: non-zero count";
  if (reinterpret_cast(filedata.get())[1] != 3)
    return "error in header: num_slots != 3";
  if (reinterpret_cast(filedata.get())[2] != 0)
    return "error in header: non-zero format version";
  // Period (slot 3) can have any value.
  if (reinterpret_cast(filedata.get())[4] != 0)
    return "error in header: non-zero padding value";
  ssize_t cur_offset = 5 * sizeof(ProfileDataSlot);

  // While there are samples, skip them.  Each sample consists of
  // at least three slots.
  bool seen_trailer = false;
  while (!seen_trailer) {
    if (cur_offset > filesize - 3 * sizeof(ProfileDataSlot))
      return "truncated sample header";
    ProfileDataSlot* sample =
        reinterpret_cast(filedata.get() + cur_offset);
    ProfileDataSlot slots_this_sample = 2 + sample[1];
    ssize_t size_this_sample = slots_this_sample * sizeof(ProfileDataSlot);
    if (cur_offset > filesize - size_this_sample)
      return "truncated sample";

    if (sample[0] == 0 && sample[1] == 1 && sample[2] == 0) {
      seen_trailer = true;
    } else {
      if (sample[0] < 1)
        return "error in sample: sample count < 1";
      if (sample[1] < 1)
        return "error in sample: num_pcs < 1";
      for (int i = 2; i < slots_this_sample; i++) {
        if (sample[i] == 0)
          return "error in sample: NULL PC";
      }
    }
    cur_offset += size_this_sample;
  }

  // There must be at least one line in the (text) list of mapped objects,
  // and it must be terminated by a newline.  Note, the use of newline
  // here and below Might not be reasonable on non-UNIX systems.
  if (cur_offset >= filesize)
    return "no list of mapped objects";
  if (filedata[filesize - 1] != '\n')
    return "profile did not end with a complete line";

  while (cur_offset < filesize) {
    char* line_start = filedata.get() + cur_offset;

    // Find the end of the line, and replace it with a NUL for easier
    // scanning.
    char* line_end = strchr(line_start, '\n');
    *line_end = '\0';

    // Advance past any leading space.  It's allowed in some lines,
    // but not in others.
    bool has_leading_space = false;
    char* line_cur = line_start;
    while (*line_cur == ' ') {
      has_leading_space = true;
      line_cur++;
    }

    bool found_match = false;

    // Check for build lines.
    if (!found_match) {
      found_match = (strncmp(line_cur, "build=", 6) == 0);
      // Anything may follow "build=", and leading space is allowed.
    }

    // A line from ProcMapsIterator::FormatLine, of the form:
    //
    // 40000000-40015000 r-xp 00000000 03:01 12845071   /lib/ld-2.3.2.so
    //
    // Leading space is not allowed.  The filename may be omitted or
    // may consist of multiple words, so we scan only up to the
    // space before the filename.
    if (!found_match) {
      int chars_scanned = -1;
      sscanf(line_cur, "%*x-%*x %*c%*c%*c%*c %*x %*x:%*x %*d %n",
             &chars_scanned);
      found_match = (chars_scanned > 0 && !has_leading_space);
    }

    // A line from DumpAddressMap, of the form:
    //
    // 40000000-40015000: /lib/ld-2.3.2.so
    //
    // Leading space is allowed.  The filename may be omitted or may
    // consist of multiple words, so we scan only up to the space
    // before the filename.
    if (!found_match) {
      int chars_scanned = -1;
      sscanf(line_cur, "%*x-%*x: %n", &chars_scanned);
      found_match = (chars_scanned > 0);
    }

    if (!found_match)
      return "unrecognized line in text section";

    cur_offset += (line_end - line_start) + 1;
  }

  return kNoError;
}

class ProfileDataTest : public testing::Test {
 protected:
  void ExpectStopped() {
    EXPECT_FALSE(collector_.enabled());
  }

  void ExpectRunningSamples(int samples) {
    ProfileData::State state;
    collector_.GetCurrentState(&state);
    EXPECT_TRUE(state.enabled);
    EXPECT_EQ(samples, state.samples_gathered);
  }

  void ExpectSameState(const ProfileData::State& before,
                       const ProfileData::State& after) {
    EXPECT_EQ(before.enabled, after.enabled);
    EXPECT_EQ(before.samples_gathered, after.samples_gathered);
    EXPECT_EQ(before.start_time, after.start_time);
    EXPECT_STREQ(before.profile_name, after.profile_name);
  }

  ProfileData        collector_;
  ProfileDataChecker checker_;
};

// Check that various operations are safe when stopped.
TEST_F(ProfileDataTest, OpsWhenStopped) {
  ExpectStopped();
  EXPECT_FALSE(collector_.enabled());

  // Verify that state is disabled, all-empty/all-0
  ProfileData::State state_before;
  collector_.GetCurrentState(&state_before);
  EXPECT_FALSE(state_before.enabled);
  EXPECT_EQ(0, state_before.samples_gathered);
  EXPECT_EQ(0, state_before.start_time);
  EXPECT_STREQ("", state_before.profile_name);

  // Safe to call stop again.
  collector_.Stop();

  // Safe to call FlushTable.
  collector_.FlushTable();

  // Safe to call Add.
  const void *trace[] = { V(100), V(101), V(102), V(103), V(104) };
  collector_.Add(arraysize(trace), trace);

  ProfileData::State state_after;
  collector_.GetCurrentState(&state_after);

  ExpectSameState(state_before, state_after);
}

// Start and Stop, collecting no samples.  Verify output contents.
TEST_F(ProfileDataTest, StartStopEmpty) {
  const int frequency = 1;
  ProfileDataSlot slots[] = {
    0, 3, 0, 1000000 / frequency, 0,    // binary header
    0, 1, 0                             // binary trailer
  };

  ExpectStopped();
  ProfileData::Options options;
  options.set_frequency(frequency);
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  ExpectRunningSamples(0);
  collector_.Stop();
  ExpectStopped();
  EXPECT_EQ(kNoError, checker_.ValidateProfile());
  EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
}

// Start and Stop with no options, collecting no samples.  Verify
// output contents.
TEST_F(ProfileDataTest, StartStopNoOptionsEmpty) {
  // We're not requesting a specific period, implementation can do
  // whatever it likes.
  ProfileDataSlot slots[] = {
    0, 3, 0, 0 /* skipped */, 0,        // binary header
    0, 1, 0                             // binary trailer
  };
  int slots_to_skip[] = { 3 };

  ExpectStopped();
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(),
                               ProfileData::Options()));
  ExpectRunningSamples(0);
  collector_.Stop();
  ExpectStopped();
  EXPECT_EQ(kNoError, checker_.ValidateProfile());
  EXPECT_EQ(kNoError, checker_.CheckWithSkips(slots, arraysize(slots),
                                              slots_to_skip,
                                              arraysize(slots_to_skip)));
}

// Start after already started.  Should return false and not impact
// collected data or state.
TEST_F(ProfileDataTest, StartWhenStarted) {
  const int frequency = 1;
  ProfileDataSlot slots[] = {
    0, 3, 0, 1000000 / frequency, 0,    // binary header
    0, 1, 0                             // binary trailer
  };

  ProfileData::Options options;
  options.set_frequency(frequency);
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));

  ProfileData::State state_before;
  collector_.GetCurrentState(&state_before);

  options.set_frequency(frequency * 2);
  CHECK(!collector_.Start("foobar", options));

  ProfileData::State state_after;
  collector_.GetCurrentState(&state_after);
  ExpectSameState(state_before, state_after);

  collector_.Stop();
  ExpectStopped();
  EXPECT_EQ(kNoError, checker_.ValidateProfile());
  EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
}

// Like StartStopEmpty, but uses a different file name and frequency.
TEST_F(ProfileDataTest, StartStopEmpty2) {
  const int frequency = 2;
  ProfileDataSlot slots[] = {
    0, 3, 0, 1000000 / frequency, 0,    // binary header
    0, 1, 0                             // binary trailer
  };

  ExpectStopped();
  ProfileData::Options options;
  options.set_frequency(frequency);
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  ExpectRunningSamples(0);
  collector_.Stop();
  ExpectStopped();
  EXPECT_EQ(kNoError, checker_.ValidateProfile());
  EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
}

TEST_F(ProfileDataTest, CollectOne) {
  const int frequency = 2;
  ProfileDataSlot slots[] = {
    0, 3, 0, 1000000 / frequency, 0,    // binary header
    1, 5, 100, 101, 102, 103, 104,      // our sample
    0, 1, 0                             // binary trailer
  };

  ExpectStopped();
  ProfileData::Options options;
  options.set_frequency(frequency);
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  ExpectRunningSamples(0);

  const void *trace[] = { V(100), V(101), V(102), V(103), V(104) };
  collector_.Add(arraysize(trace), trace);
  ExpectRunningSamples(1);

  collector_.Stop();
  ExpectStopped();
  EXPECT_EQ(kNoError, checker_.ValidateProfile());
  EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
}

TEST_F(ProfileDataTest, CollectTwoMatching) {
  const int frequency = 2;
  ProfileDataSlot slots[] = {
    0, 3, 0, 1000000 / frequency, 0,    // binary header
    2, 5, 100, 201, 302, 403, 504,      // our two samples
    0, 1, 0                             // binary trailer
  };

  ExpectStopped();
  ProfileData::Options options;
  options.set_frequency(frequency);
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  ExpectRunningSamples(0);

  for (int i = 0; i < 2; ++i) {
    const void *trace[] = { V(100), V(201), V(302), V(403), V(504) };
    collector_.Add(arraysize(trace), trace);
    ExpectRunningSamples(i + 1);
  }

  collector_.Stop();
  ExpectStopped();
  EXPECT_EQ(kNoError, checker_.ValidateProfile());
  EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
}

TEST_F(ProfileDataTest, CollectTwoFlush) {
  const int frequency = 2;
  ProfileDataSlot slots[] = {
    0, 3, 0, 1000000 / frequency, 0,    // binary header
    1, 5, 100, 201, 302, 403, 504,      // first sample (flushed)
    1, 5, 100, 201, 302, 403, 504,      // second identical sample
    0, 1, 0                             // binary trailer
  };

  ExpectStopped();
  ProfileData::Options options;
  options.set_frequency(frequency);
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  ExpectRunningSamples(0);

  const void *trace[] = { V(100), V(201), V(302), V(403), V(504) };

  collector_.Add(arraysize(trace), trace);
  ExpectRunningSamples(1);
  collector_.FlushTable();

  collector_.Add(arraysize(trace), trace);
  ExpectRunningSamples(2);

  collector_.Stop();
  ExpectStopped();
  EXPECT_EQ(kNoError, checker_.ValidateProfile());
  EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
}

// Start then reset, verify that the result is *not* a valid profile.
// Then start again and make sure the result is OK.
TEST_F(ProfileDataTest, StartResetRestart) {
  ExpectStopped();
  ProfileData::Options options;
  options.set_frequency(1);
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  ExpectRunningSamples(0);
  collector_.Reset();
  ExpectStopped();
  // We expect the resulting file to be empty.  This is a minimal test
  // of ValidateProfile.
  EXPECT_NE(kNoError, checker_.ValidateProfile());

  struct stat statbuf;
  EXPECT_EQ(0, stat(checker_.filename().c_str(), &statbuf));
  EXPECT_EQ(0, statbuf.st_size);

  const int frequency = 2;  // Different frequency than used above.
  ProfileDataSlot slots[] = {
    0, 3, 0, 1000000 / frequency, 0,    // binary header
    0, 1, 0                             // binary trailer
  };

  options.set_frequency(frequency);
  EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  ExpectRunningSamples(0);
  collector_.Stop();
  ExpectStopped();
  EXPECT_EQ(kNoError, checker_.ValidateProfile());
  EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
}

}  // namespace
gperftools-gperftools-2.18/src/tests/profiler_unittest.cc000066400000000000000000000132111513545575200240450ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// Does some simple arithmetic and a few libc routines, so we can profile it.
// Define WITH_THREADS to add pthread functionality as well (otherwise, btw,
// the num_threads argument to this program is ingored).

#include "config_for_unittests.h"
#include 
#include 
#include 

#ifdef HAVE_UNISTD_H
#include                  // for fork()
#include                // for wait()
#endif

#include 

#include "gperftools/profiler.h"
#include "tests/testutil.h"

static int g_iters;   // argv[1]

// g_ticks_count points to internal profiler's tick count that
// increments each profiling tick. Makes it possible for this test
// loops to run long enough to get enough ticks.
static int volatile *g_ticks_count = ([] () {
  ProfilerState state;
  memset(&state, 0, sizeof(state));
  ProfilerGetCurrentState(&state);
  size_t sz = strlen(state.profile_name);
  if (sz + 1 + sizeof(g_ticks_count) > sizeof(state.profile_name)) {
    fprintf(stderr, "too long profile_name?: %zu (%s)\n", sz, state.profile_name);
    abort();
  }
  int volatile* ptr;
  memcpy(&ptr, state.profile_name + sz + 1, sizeof(ptr));
  return ptr;
})();

std::mutex mutex;

static void test_other_thread() {
  ProfilerRegisterThread();

  int result = 0;
  char b[128];

  std::lock_guard ml(mutex);

  // Get at least 30 ticks
  int limit = *g_ticks_count + 30;

  while (*g_ticks_count < limit) {
    for (int i = 0; i < g_iters * 10; ++i ) {
      *const_cast(&result) ^= i;
    }
    snprintf(b, sizeof(b), "other: %d", result);  // get some libc action
    (void)noopt(b); // 'consume' b. Ensure that smart compiler doesn't
                    // remove snprintf call
  }
}

static void test_main_thread() {
  int result = 0;
  char b[128];

  std::lock_guard ml(mutex);

  // Get at least 30 ticks
  int limit = *g_ticks_count + 30;

  while (*g_ticks_count < limit) {
    for (int i = 0; i < g_iters * 10; ++i ) {
      *const_cast(&result) ^= i;
    }
    snprintf(b, sizeof(b), "same: %d", result);  // get some libc action
    (void)noopt(b); // 'consume' b
  }
}



int main(int argc, char** argv) {
  if ( argc <= 1 ) {
    fprintf(stderr, "USAGE: %s  [num_threads] [filename]\n", argv[0]);
    fprintf(stderr, "   iters: How many million times to run the XOR test.\n");
    fprintf(stderr, "   num_threads: how many concurrent threads.\n");
    fprintf(stderr, "                0 or 1 for single-threaded mode,\n");
    fprintf(stderr, "                -# to fork instead of thread.\n");
    fprintf(stderr, "   filename: The name of the output profile.\n");
    fprintf(stderr, ("             If you don't specify, set CPUPROFILE "
                     "in the environment instead!\n"));
    return 1;
  }

  g_iters = atoi(argv[1]);
  int num_threads = 1;
  const char* filename = nullptr;
  if (argc > 2) {
    num_threads = atoi(argv[2]);
  }
  if (argc > 3) {
    filename = argv[3];
  }

  if (filename) {
    ProfilerStart(filename);
  }

  test_main_thread();

  ProfilerFlush();                           // just because we can

  // The other threads, if any, will run only half as long as the main thread
  if(num_threads > 0) {
    RunManyThreads(test_other_thread, num_threads);
  } else {
  // Or maybe they asked to fork.  The fork test is only interesting
  // when we use CPUPROFILE to name, so check for that
#ifdef HAVE_UNISTD_H
    for (; num_threads < 0; ++num_threads) {   // - to fork
      if (filename) {
        printf("FORK test only makes sense when no filename is specified.\n");
        return 2;
      }
      switch (fork()) {
        case -1:
          printf("FORK failed!\n");
          return 1;
        case 0:             // child
          return execl(argv[0], argv[0], argv[1], nullptr);
        default:
          wait(nullptr);       // we'll let the kids run one at a time
      }
    }
#else
    fprintf(stderr, "%s was compiled without support for fork() and exec()\n", argv[0]);
#endif
  }

  test_main_thread();

  if (filename) {
    ProfilerStop();
  }

  return 0;
}
gperftools-gperftools-2.18/src/tests/profiler_unittest.sh000077500000000000000000000160261513545575200241040ustar00rootroot00000000000000#!/bin/sh

# Copyright (c) 2005, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# ---
# Author: Craig Silverstein
#
# Runs the 4 profiler unittests and makes sure their profiles look
# appropriate.  We expect two commandline args, as described below.
#
# We run under the assumption that if $PROFILER1 is run with no
# arguments, it prints a usage line of the form
#   USAGE:  [...]
#
# This is because libtool sometimes turns the 'executable' into a
# shell script which runs an actual binary somewhere else.

# We expect BINDIR and PPROF_PATH to be set in the environment.
# If not, we set them to some reasonable values
BINDIR="${BINDIR:-.}"
PPROF_PATH="${PPROF_PATH:-pprof}"

if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
  echo "USAGE: $0 [unittest dir] [path to pprof]"
  echo "       By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH"
  exit 1
fi

# note, this also creates temp directory
TMPDIR=`mktemp -d`

UNITTEST_DIR=${1:-$BINDIR}
PPROF=${2:-$PPROF_PATH}

PROFILER="$UNITTEST_DIR/profiler_unittest"

# It's meaningful to the profiler, so make sure we know its state
unset CPUPROFILE

num_failures=0

RegisterFailure() {
  num_failures=`expr $num_failures + 1`
}

# Takes two filenames representing profiles, with their executable scripts,
# and a multiplier, and verifies that the 'contentful' functions in each
# profile take the same time (possibly scaled by the given multiplier). It
# used to be "same" meant within 50%, after adding an noise-reducing X units
# to each value.  But even that would often spuriously fail, so now it's
# "both non-zero". We're pretty forgiving.
VerifySimilar() {
  prof1="$TMPDIR/$1"
  prof2="$TMPDIR/$2"
  mult="$3"

  mthread1=`"$PPROF" --unit=ms --text "$prof1" | grep test_main_thread | awk '{print $1}' | sed 's/ms//g'`
  mthread2=`"$PPROF" --unit=ms --text "$prof2" | grep test_main_thread | awk '{print $1}' | sed 's/ms//g'`
  mthread1_plus=`expr $mthread1 + 5`
  mthread2_plus=`expr $mthread2 + 5`
  if [ -z "$mthread1" ] || [ -z "$mthread2" ] || \
     [ "$mthread1" -le 0 -o "$mthread2" -le 0 ]
#    || [ `expr $mthread1_plus \* $mult` -gt `expr $mthread2_plus \* 2` -o \
#         `expr $mthread1_plus \* $mult \* 2` -lt `expr $mthread2_plus` ]
  then
    echo
    echo ">>> profile on profiler_unittest with multiplier $mult failed:"
    echo "Actual times (in profiling units) were '$mthread1' vs. '$mthread2'"
    echo
    RegisterFailure
  fi
}

# Takes a filename representing a profile, with its executable,
# and a multiplier, and verifies that the main-thread function takes
# the same amount of time as the other-threads function (possibly scaled
# by the given multiplier).  Figuring out the multiplier can be tricky,
# since by design the main thread runs twice as long as each of the
# 'other' threads!  It used to be "same" meant within 50%, after adding an 
# noise-reducing X units to each value.  But even that would often
# spuriously fail, so now it's "both non-zero".  We're pretty forgiving.
VerifyAcrossThreads() {
  prof1="$TMPDIR/$1"
  # We need to run the script with no args to get the actual exe name
  mult="$2"

  mthread=`$PPROF --unit=ms --text "$prof1" | grep test_main_thread | awk '{print $1}' | sed 's/ms//g'`
  othread=`$PPROF --unit=ms --text "$prof1" | grep test_other_thread | awk '{print $1}' | sed 's/ms//g'`
  if [ -z "$mthread" ] || [ -z "$othread" ] || \
     [ "$mthread" -le 0 -o "$othread" -le 0 ]
#    || [ `expr $mthread \* $mult \* 3` -gt `expr $othread \* 10` -o \
#         `expr $mthread \* $mult \* 10` -lt `expr $othread \* 3` ]
  then
    echo
    echo ">>> profile on profiler_unittest (main vs thread) with multiplier $mult failed:"
    echo "Actual times (in profiling units) were '$mthread' vs. '$othread'"
    echo
    RegisterFailure
  fi
}

# profiler1 is a non-threaded version
"$PROFILER" 50 1 "$TMPDIR/p1" || RegisterFailure
"$PROFILER" 100 1 "$TMPDIR/p2" || RegisterFailure
VerifySimilar p1 p2 2

# Verify the same thing works if we specify via CPUPROFILE
CPUPROFILE="$TMPDIR/p5" "$PROFILER" 50 || RegisterFailure
CPUPROFILE="$TMPDIR/p6" "$PROFILER" 100 || RegisterFailure
VerifySimilar p5 p6 2

CPUPROFILE="$TMPDIR/p5b" "$PROFILER" 30 || RegisterFailure
CPUPROFILE="$TMPDIR/p5c" "$PROFILER" 60 || RegisterFailure
VerifySimilar p5b p5c 2

# Now try what happens when we use threads
"$PROFILER" 30 2 "$TMPDIR/p7" || RegisterFailure
"$PROFILER" 60 2 "$TMPDIR/p8" || RegisterFailure
VerifySimilar p7 p8 2

# More threads!
"$PROFILER" 25 3 "$TMPDIR/p9" || RegisterFailure
"$PROFILER" 50 3 "$TMPDIR/p10" || RegisterFailure
VerifySimilar p9 p10 2

# Compare how much time the main thread takes compared to the other threads
# Recall the main thread runs twice as long as the other threads, by design.
"$PROFILER" 20 4 "$TMPDIR/p11" || RegisterFailure
VerifyAcrossThreads p11 2

# Test using ITIMER_REAL instead of ITIMER_PROF.
env CPUPROFILE_REALTIME=1 "$PROFILER" 30 2 "$TMPDIR/p16" || RegisterFailure
env CPUPROFILE_REALTIME=1 "$PROFILER" 60 2 "$TMPDIR/p17" || RegisterFailure
VerifySimilar p16 p17 2


# NetBSD has slightly borked environ access when we're updating it
# early. See
# https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=59599
if [ `uname` = NetBSD ]
then
  export CPUPROFILE_USE_PID=1
fi

# Make sure that when we have a process with a fork, the profiles don't
# clobber each other
CPUPROFILE="$TMPDIR/pfork" "$PROFILER" 1 -2 || RegisterFailure
n=`ls $TMPDIR/pfork* | wc -l | tr -d '[:space:]'`
if [ $n != 3 ]; then
  echo "FORK test FAILED: expected 3 profiles (for main + 2 children), found $n"
  num_failures=`expr $num_failures + 1`
fi

rm -rf "$TMPDIR"      # clean up

echo "Tests finished with $num_failures failures"
exit $num_failures
gperftools-gperftools-2.18/src/tests/realloc_unittest.cc000066400000000000000000000077711513545575200236620ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2004, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// Test realloc() functionality

#include "config_for_unittests.h"

#include 
#include 
#include 
#include 

#include "tests/testutil.h"
#include "gtest/gtest.h"

// Fill a buffer of the specified size with a predetermined pattern
static void Fill(unsigned char* buffer, int n) {
  for (int i = 0; i < n; i++) {
    buffer[i] = (i & 0xff);
  }
}

// Check that the specified buffer has the predetermined pattern
// generated by Fill()
static bool Valid(unsigned char* buffer, int n) {
  for (int i = 0; i < n; i++) {
    if (buffer[i] != (i & 0xff)) {
      return false;
    }
  }
  return true;
}

// Return the next interesting size/delta to check.  Returns -1 if no more.
static int NextSize(int size) {
  if (size < 100) {
    return size+1;
  } else if (size < 100000) {
    // Find next power of two
    int power = 1;
    while (power < size) {
      power <<= 1;
    }

    // Yield (power-1, power, power+1)
    if (size < power-1) {
      return power-1;
    } else if (size == power-1) {
      return power;
    } else {
      assert(size == power);
      return power+1;
    }
  } else {
    return -1;
  }
}

TEST(ReallocUnittest, Basics) {
  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
      unsigned char* src = (unsigned char*) malloc(src_size);
      Fill(src, src_size);
      unsigned char* dst = (unsigned char*) realloc(src, dst_size);
      ASSERT_TRUE(Valid(dst, std::min(src_size, dst_size)));
      Fill(dst, dst_size);
      ASSERT_TRUE(Valid(dst, dst_size));
      if (dst != nullptr) free(dst);
    }
  }

  // Now make sure realloc works correctly even when we overflow the
  // packed cache, so some entries are evicted from the cache.
  // The cache has 2^12 entries, keyed by page number.
  const int kNumEntries = 1 << 14;
  int** p = (int**)noopt(malloc(sizeof(*p) * kNumEntries));
  int sum = 0;
  for (int i = 0; i < kNumEntries; i++) {
    p[i] = (int*)malloc(8192);   // no page size is likely to be bigger
    p[i][1000] = i;              // use memory deep in the heart of p
  }
  for (int i = 0; i < kNumEntries; i++) {
    p[i] = (int*)noopt(realloc(p[i], 9000));
  }
  for (int i = 0; i < kNumEntries; i++) {
    sum += p[i][1000];
    free(p[i]);
  }
  ASSERT_EQ(kNumEntries/2 * (kNumEntries - 1), sum);  // assume kNE is even
  free(p);
}
gperftools-gperftools-2.18/src/tests/safe_strerror_test.cc000066400000000000000000000036571513545575200242200ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2023, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config_for_unittests.h"

#include "safe_strerror.h"

#include 

#include 

#include "gtest/gtest.h"

TEST(SafeStrerrorTest, Basic) {
  ASSERT_EQ(std::string{tcmalloc::SafeStrError(ENOMEM).c_str()}, "ENOMEM");
  ASSERT_EQ(std::string{tcmalloc::SafeStrError(999999999).c_str()}, "errno 999999999");
}

gperftools-gperftools-2.18/src/tests/sampler_test.cc000066400000000000000000000424661513545575200230040ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// All Rights Reserved.
//
// Author: Daniel Ford
//
// Checks basic properties of the sampler

#include "config_for_unittests.h"

#include "sampler.h"

#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 

#include "base/commandlineflags.h"

#include "gtest/gtest.h"

#undef LOG   // defined in base/logging.h
// Ideally, we'd put the newline at the end, but this hack puts the
// newline at the end of the previous log message, which is good enough :-)
#define LOG(level)  std::cerr << "\n"

static std::string StringPrintf(const char* format, ...) {
  char buf[256];   // should be big enough for all logging
  va_list ap;
  va_start(ap, format);
  vsnprintf(buf, sizeof(buf), format, ap);
  va_end(ap);
  return buf;
}

// Note that these tests are stochastic.
// This mean that the chance of correct code passing the test is,
// in the case of 5 standard deviations:
// kSigmas=5:    ~99.99994267%
// in the case of 4 standard deviations:
// kSigmas=4:    ~99.993666%
static const double kSigmas = 4;
static const size_t kSamplingInterval = 512*1024;

DECLARE_int64(tcmalloc_sample_parameter);

class SamplerTest : public ::testing::Test {
public:
  void SetUp() {
    // Make sure Sampler's TrivialOnce logic runs before we're messing
    // up with sample parameter.
    tcmalloc::Sampler{}.Init(1);

    old_parameter_ = 512 << 10;
    std::swap(old_parameter_, FLAGS_tcmalloc_sample_parameter);
  }
  void TearDown() {
    std::swap(old_parameter_, FLAGS_tcmalloc_sample_parameter);
  }
private:
  int64_t old_parameter_;
};

// Tests that GetSamplePeriod returns the expected value
// which is 1<<19
TEST_F(SamplerTest, TestGetSamplePeriod) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  uint64_t sample_period;
  sample_period = sampler.GetSamplePeriod();
  ASSERT_GT(sample_period, 0);
}

// Tests of the quality of the random numbers generated
// This uses the Anderson Darling test for uniformity.
// See "Evaluating the Anderson-Darling Distribution" by Marsaglia
// for details.

// Short cut version of ADinf(z), z>0 (from Marsaglia)
// This returns the p-value for Anderson Darling statistic in
// the limit as n-> infinity. For finite n, apply the error fix below.
double AndersonDarlingInf(double z) {
  if (z < 2) {
    return exp(-1.2337141 / z) / sqrt(z) * (2.00012 + (0.247105 -
                (0.0649821 - (0.0347962 - (0.011672 - 0.00168691
                * z) * z) * z) * z) * z);
  }
  return exp( - exp(1.0776 - (2.30695 - (0.43424 - (0.082433 -
                    (0.008056 - 0.0003146 * z) * z) * z) * z) * z));
}

// Corrects the approximation error in AndersonDarlingInf for small values of n
// Add this to AndersonDarlingInf to get a better approximation
// (from Marsaglia)
double AndersonDarlingErrFix(int n, double x) {
  if (x > 0.8) {
    return (-130.2137 + (745.2337 - (1705.091 - (1950.646 -
            (1116.360 - 255.7844 * x) * x) * x) * x) * x) / n;
  }
  double cutoff = 0.01265 + 0.1757 / n;
  double t;
  if (x < cutoff) {
    t = x / cutoff;
    t = sqrt(t) * (1 - t) * (49 * t - 102);
    return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n;
  } else {
    t = (x - cutoff) / (0.8 - cutoff);
    t = -0.00022633 + (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864
          * t) * t) * t) * t) * t;
    return t * (0.04213 + 0.01365 / n) / n;
  }
}

// Returns the AndersonDarling p-value given n and the value of the statistic
double AndersonDarlingPValue(int n, double z) {
  double ad = AndersonDarlingInf(z);
  double errfix = AndersonDarlingErrFix(n, ad);
  return ad + errfix;
}

double AndersonDarlingStatistic(int n, double* random_sample) {
  double ad_sum = 0;
  for (int i = 0; i < n; i++) {
    ad_sum += (2*i + 1) * log(random_sample[i] * (1 - random_sample[n-1-i]));
  }
  double ad_statistic = - n - 1/static_cast(n) * ad_sum;
  return ad_statistic;
}

// Tests if the array of doubles is uniformly distributed.
// Returns the p-value of the Anderson Darling Statistic
// for the given set of sorted random doubles
// See "Evaluating the Anderson-Darling Distribution" by
// Marsaglia and Marsaglia for details.
double AndersonDarlingTest(int n, double* random_sample) {
  double ad_statistic = AndersonDarlingStatistic(n, random_sample);
  LOG(INFO) << StringPrintf("AD stat = %f, n=%d\n", ad_statistic, n);
  double p = AndersonDarlingPValue(n, ad_statistic);
  return p;
}

// Test the AD Test. The value of the statistic should go to zero as n->infty
// Not run as part of regular tests
void ADTestTest(int n) {
  std::unique_ptr random_sample(new double[n]);
  for (int i = 0; i < n; i++) {
    random_sample[i] = (i+0.01)/n;
  }
  std::sort(random_sample.get(), random_sample.get() + n);
  double ad_stat = AndersonDarlingStatistic(n, random_sample.get());
  LOG(INFO) << StringPrintf("Testing the AD test. n=%d, ad_stat = %f",
                            n, ad_stat);
}

// Print the CDF of the distribution of the Anderson-Darling Statistic
// Used for checking the Anderson-Darling Test
// Not run as part of regular tests
void ADCDF() {
  for (int i = 1; i < 40; i++) {
    double x = i/10.0;
    LOG(INFO) << "x= " << x << "  adpv= "
              << AndersonDarlingPValue(100, x) << ", "
              << AndersonDarlingPValue(1000, x);
  }
}

// Testing that NextRandom generates uniform
// random numbers.
// Applies the Anderson-Darling test for uniformity
void TestNextRandom(int n) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  uint64_t x = 1;
  // This assumes that the prng returns 48 bit numbers
  uint64_t max_prng_value = static_cast(1)<<48;
  // Initialize
  for (int i = 1; i <= 20; i++) {  // 20 mimics sampler.Init()
    x = sampler.NextRandom(x);
  }
  std::unique_ptr int_random_sample(new uint64_t[n]);
  // Collect samples
  for (int i = 0; i < n; i++) {
    int_random_sample[i] = x;
    x = sampler.NextRandom(x);
  }
  // First sort them...
  std::sort(int_random_sample.get(), int_random_sample.get() + n);
  std::unique_ptr random_sample(new double[n]);
  // Convert them to uniform randoms (in the range [0,1])
  for (int i = 0; i < n; i++) {
    random_sample[i] = static_cast(int_random_sample[i])/max_prng_value;
  }
  // Now compute the Anderson-Darling statistic
  double ad_pvalue = AndersonDarlingTest(n, random_sample.get());
  LOG(INFO) << StringPrintf("pvalue for AndersonDarlingTest "
                            "with n= %d is p= %f\n", n, ad_pvalue);
  ASSERT_GT(std::min(ad_pvalue, 1 - ad_pvalue), 0.0001)
            << StringPrintf("prng is not uniform, %d\n", n);
}


TEST_F(SamplerTest, TestNextRandom_MultipleValues) {
  ASSERT_NO_FATAL_FAILURE(TestNextRandom(10));  // Check short-range correlation
  ASSERT_NO_FATAL_FAILURE(TestNextRandom(100));
  ASSERT_NO_FATAL_FAILURE(TestNextRandom(1000));
  ASSERT_NO_FATAL_FAILURE(TestNextRandom(10000));  // Make sure there's no systematic error
}

// Tests that PickNextSamplePeriod generates
// geometrically distributed random numbers.
// First converts to uniforms then applied the
// Anderson-Darling test for uniformity.
void TestPickNextSample(int n) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  std::unique_ptr int_random_sample(new uint64_t[n]);
  int sample_period = sampler.GetSamplePeriod();
  int ones_count = 0;
  for (int i = 0; i < n; i++) {
    int_random_sample[i] = sampler.PickNextSamplingPoint();
    ASSERT_GE(int_random_sample[i], 1);
    if (int_random_sample[i] == 1) {
      ones_count += 1;
    }
    ASSERT_LT(ones_count, 4) << " out of " << i << " samples.";
  }
  // First sort them...
  std::sort(int_random_sample.get(), int_random_sample.get() + n);
  std::unique_ptr random_sample(new double[n]);
  // Convert them to uniform random numbers
  // by applying the geometric CDF
  for (int i = 0; i < n; i++) {
    random_sample[i] = 1 - exp(-static_cast(int_random_sample[i])
                           / sample_period);
  }
  // Now compute the Anderson-Darling statistic
  double geom_ad_pvalue = AndersonDarlingTest(n, random_sample.get());
  LOG(INFO) << StringPrintf("pvalue for geometric AndersonDarlingTest "
                             "with n= %d is p= %f\n", n, geom_ad_pvalue);
  ASSERT_GT(std::min(geom_ad_pvalue, 1 - geom_ad_pvalue), 0.0001)
               << "PickNextSamplingPoint does not produce good "
                  "geometric/exponential random numbers\n";
}

TEST_F(SamplerTest, TestPickNextSample_MultipleValues) {
  ASSERT_NO_FATAL_FAILURE(TestPickNextSample(10));  // Make sure the first few are good (enough)
  ASSERT_NO_FATAL_FAILURE(TestPickNextSample(100));
  ASSERT_NO_FATAL_FAILURE(TestPickNextSample(1000));
  ASSERT_NO_FATAL_FAILURE(TestPickNextSample(10000));  // Make sure there's no systematic erro)r
}


// Futher tests

bool CheckMean(size_t mean, int num_samples) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  size_t total = 0;
  for (int i = 0; i < num_samples; i++) {
    total += sampler.PickNextSamplingPoint();
  }
  double empirical_mean = total / static_cast(num_samples);
  double expected_sd = mean / pow(num_samples * 1.0, 0.5);
  return(fabs(mean-empirical_mean) < expected_sd * kSigmas);
}

// Prints a sequence so you can look at the distribution
void OutputSequence(int sequence_length) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  size_t next_step;
  for (int i = 0; i< sequence_length; i++) {
    next_step = sampler.PickNextSamplingPoint();
    LOG(INFO) << next_step;
  }
}


double StandardDeviationsErrorInSample(
              int total_samples, int picked_samples,
              int alloc_size, int sampling_interval) {
  double p = 1 - exp(-(static_cast(alloc_size) / sampling_interval));
  double expected_samples = total_samples * p;
  double sd = pow(p*(1-p)*total_samples, 0.5);
  return((picked_samples - expected_samples) / sd);
}

TEST_F(SamplerTest, LargeAndSmallAllocs_CombinedTest) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  int counter_big = 0;
  int counter_small = 0;
  int size_big = 129*8*1024+1;
  int size_small = 1024*8;
  int num_iters = 128*4*8;
  // Allocate in mixed chunks
  for (int i = 0; i < num_iters; i++) {
    if (!sampler.RecordAllocation(size_big)) {
      counter_big += 1;
    }
    for (int i = 0; i < 129; i++) {
      if (!sampler.RecordAllocation(size_small)) {
        counter_small += 1;
      }
    }
  }
  // Now test that there are the right number of each
  double large_allocs_sds =
     StandardDeviationsErrorInSample(num_iters, counter_big,
                                     size_big, kSamplingInterval);
  double small_allocs_sds =
     StandardDeviationsErrorInSample(num_iters*129, counter_small,
                                     size_small, kSamplingInterval);
  LOG(INFO) << StringPrintf("large_allocs_sds = %f\n", large_allocs_sds);
  LOG(INFO) << StringPrintf("small_allocs_sds = %f\n", small_allocs_sds);
  ASSERT_LE(fabs(large_allocs_sds), kSigmas);
  ASSERT_LE(fabs(small_allocs_sds), kSigmas);
}

// Tests whether the mean is about right over 1000 samples
TEST_F(SamplerTest, IsMeanRight) {
  ASSERT_TRUE(CheckMean(kSamplingInterval, 1000));
}

// This checks that the stated maximum value for the
// tcmalloc_sample_parameter flag never overflows bytes_until_sample_
TEST_F(SamplerTest, bytes_until_sample_Overflow_Underflow) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  uint64_t one = 1;
  // sample_parameter = 0;  // To test the edge case
  uint64_t sample_parameter_array[4] = {0, 1, one<<19, one<<58};
  for (int i = 0; i < 4; i++) {
    uint64_t sample_parameter = sample_parameter_array[i];
    LOG(INFO) << "sample_parameter = " << sample_parameter;
    double sample_scaling = - log(2.0) * sample_parameter;
    // Take the top 26 bits as the random number
    // (This plus the 1<<26 sampling bound give a max step possible of
    // 1209424308 bytes.)
    const uint64_t prng_mod_power = 48;  // Number of bits in prng

    // First, check the largest_prng value
    uint64_t largest_prng_value = (static_cast(1)<<48) - 1;
    double q = (largest_prng_value >> (prng_mod_power - 26)) + 1.0;
    LOG(INFO) << StringPrintf("q = %f\n", q);
    LOG(INFO) << StringPrintf("log2(q) = %f\n", log(q)/log(2.0));
    uint64_t smallest_sample_step
      = static_cast(std::min(log2(q) - 26, 0.0)
                              * sample_scaling + 1);
    LOG(INFO) << "Smallest sample step is " << smallest_sample_step;
    uint64_t cutoff = static_cast(10)
                      * (sample_parameter/(one<<24) + 1);
    LOG(INFO) << "Acceptable value is < " << cutoff;
    // This checks that the answer is "small" and positive
    ASSERT_LE(smallest_sample_step, cutoff);

    // Next, check with the smallest prng value
    uint64_t smallest_prng_value = 0;
    q = (smallest_prng_value >> (prng_mod_power - 26)) + 1.0;
    LOG(INFO) << StringPrintf("q = %f\n", q);
    uint64_t largest_sample_step
      = static_cast(std::min(log2(q) - 26, 0.0)
                              * sample_scaling + 1);
    LOG(INFO) << "Largest sample step is " << largest_sample_step;
    ASSERT_LE(largest_sample_step, one<<63);
    ASSERT_GE(largest_sample_step, smallest_sample_step);
  }
}


// Test that NextRand is in the right range.  Unfortunately, this is a
// stochastic test which could miss problems.
TEST_F(SamplerTest, NextRand_range) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  uint64_t one = 1;
  // The next number should be (one << 48) - 1
  uint64_t max_value = (one << 48) - 1;
  uint64_t x = (one << 55);
  int n = 22;  // 27;
  LOG(INFO) << "Running sampler.NextRandom 1<<" << n << " times";
  for (int i = 1; i <= (1<>27); i++) {  // 20 mimics sampler.Init()
    rnd = sampler.NextRandom(rnd);
    ASSERT_LE(rnd, max_value);
    double q = (rnd >> (prng_mod_power - 26)) + 1.0;
    ASSERT_GE(q, 0) << rnd << "  " << prng_mod_power;
  }
  // Test some potentially out of bounds value for rnd
  for (int i = 1; i <= 63; i++) {
    rnd = one << i;
    double q = (rnd >> (prng_mod_power - 26)) + 1.0;
    LOG(INFO) << "rnd = " << rnd << " i=" << i << " q=" << q;
    ASSERT_GE(q, 0)
      << " rnd=" << rnd << "  i=" << i << " prng_mod_power" << prng_mod_power;
  }
}

void test_arithmetic(uint64_t rnd) {
  const uint64_t prng_mod_power = 48;  // Number of bits in prng
  uint64_t shifted_rnd = rnd >> (prng_mod_power - 26);
  ASSERT_GE(shifted_rnd, 0);
  ASSERT_LT(shifted_rnd, (1<<26));
  LOG(INFO) << shifted_rnd;
  LOG(INFO) << static_cast(shifted_rnd);
  ASSERT_GE(static_cast(static_cast(shifted_rnd)), 0)
    << " rnd=" << rnd << "  srnd=" << shifted_rnd;
  ASSERT_GE(static_cast(shifted_rnd), 0)
    << " rnd=" << rnd << "  srnd=" << shifted_rnd;
  double q = static_cast(shifted_rnd) + 1.0;
  ASSERT_GT(q, 0);
}

// Tests certain arithmetic operations to make sure they compute what we
// expect them too (for testing across different platforms)
// know bad values under with -c dbg --cpu piii for _some_ binaries:
// rnd=227453640600554
// shifted_rnd=54229173
// (hard to reproduce)
TEST_F(SamplerTest, arithmetic_2) {
  uint64_t rnd = 227453640600554LL;
  test_arithmetic(rnd);
}


// It's not really a test, but it's good to know
TEST_F(SamplerTest, size_of_class) {
  tcmalloc::Sampler sampler;
  sampler.Init(1);
  LOG(INFO) << "Size of Sampler class is: " << sizeof(tcmalloc::Sampler);
  LOG(INFO) << "Size of Sampler object is: " << sizeof(sampler);
}
gperftools-gperftools-2.18/src/tests/sampling_test.cc000066400000000000000000000147061513545575200231470ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// This tests ReadStackTraces and ReadGrowthStackTraces.  It does this
// by doing a bunch of allocations and then calling those functions.
// A driver shell-script can call this, and then call pprof, and
// verify the expected output.  The output is written to
// argv[1].heap and argv[1].growth

#include "config_for_unittests.h"

#include "gperftools/malloc_extension.h"

#include 
#include 
#include 

#include 
#include 
#include 

#include "tests/testutil.h"

#include "base/logging.h"
#include "base/cleanup.h"
#include "testing_portal.h"

static std::string NaiveShellQuote(std::string_view arg) {
  // We're naive, so don't support paths with quote char. With that
  // we're able to quote by simply wrapping things with quotes.
  CHECK_EQ(arg.find('"'), std::string_view::npos);
  std::string retval({'"'});
  retval.append(arg);
  retval.append({'"'});
  return retval;
}

extern "C" ATTRIBUTE_NOINLINE
void* AllocateAllocate() {
  auto local_noopt = [] (void* ptr) ATTRIBUTE_NOINLINE {
    return noopt(ptr);
  };
  return local_noopt(malloc(10000));
}

#ifndef PPROF_PATH
#define PPROF_PATH pprof
#endif

#define XSTR(x) #x
#define STR(x) XSTR(x)

const char kPProfPath[] = STR(PPROF_PATH);

static void VerifyWithPProf(std::string_view argv0, std::string_view path) {
  std::string cmdline = NaiveShellQuote(kPProfPath) + " --text " + NaiveShellQuote(argv0) + " " + NaiveShellQuote(path);
  printf("pprof cmdline: %s\n", cmdline.c_str());
  FILE* p = popen(cmdline.c_str(), "r");
  if (!p) {
    perror("popen");
    abort();
  }
  tcmalloc::Cleanup close_pipe([p] () { (void)pclose(p); });

  constexpr int kBufSize = 1024;
  std::string contents;
  char buf[kBufSize];
  while (!feof(p)) {
    size_t amt = fread(buf, 1, kBufSize, p);
    contents.append(buf, buf + amt);
  }

  fprintf(stderr, "pprof output:\n%s\n\n", contents.c_str());

  regmatch_t pmatch[3];
  regex_t regex;
  CHECK_EQ(regcomp(®ex, "([0-9.]+)(MB)? *([0-9.]+)% *_*AllocateAllocate", REG_NEWLINE | REG_EXTENDED), 0);
  CHECK_EQ(regexec(®ex, contents.c_str(), 3, pmatch, 0), 0);

  fprintf(stderr,"AllocateAllocate regex match: %.*s\n",
          int(pmatch[0].rm_eo - pmatch[0].rm_so),
          contents.data() + pmatch[0].rm_so);

  std::string number{contents.data() + pmatch[1].rm_so, contents.data() + pmatch[1].rm_eo};

  errno = 0;
  char* endptr;
  double megs = strtod(number.c_str(), &endptr);
  CHECK(endptr && *endptr == '\0');
  CHECK_EQ(errno, 0);

  // We allocate 8*10^7 bytes of memory, which is 76M.  Because we
  // sample, the estimate may be a bit high or a bit low: we accept
  // anything from 50M to 109M.
  if (!(50 <= megs && megs < 110)) {
    fprintf(stderr, "expected megs to be between 50 and 110. Got: %f\n", megs);
    abort();
  }
}

struct TempFile {
  FILE* f;
  std::string const path;

  TempFile(FILE* f, std::string_view path) : f(f), path(path) {}

  ~TempFile() {
    if (f) {
      (void)fclose(f);
    }
  }

  FILE* ReleaseFile() {
    FILE* retval = f;
    f = nullptr;
    return retval;
  }

  static TempFile Create(std::string_view base_template) {
    CHECK_EQ(base_template.substr(base_template.size() - 6), "XXXXXX");

    const char* raw_tmpdir = getenv("TMPDIR");
    if (raw_tmpdir == nullptr) {
      raw_tmpdir = "/tmp";
    }
    std::string_view tmpdir{raw_tmpdir};
    size_t len = tmpdir.size() + 1 + base_template.size() + 1;
    std::unique_ptr path_template{new char[len]};
    auto it = std::copy(tmpdir.begin(), tmpdir.end(), path_template.get());
    *it++ = '/';
    it = std::copy(base_template.begin(), base_template.end(), it);
    *it++ = '\0';
    CHECK_EQ(it, path_template.get() + len);

    int fd = mkstemp(path_template.get());
    if (fd < 0) {
      perror("mkstemp");
    }
    CHECK_GE(fd, 0);

    return TempFile{fdopen(fd, "r+"), std::string(path_template.get(), len-1)};
  }
};

int main(int argc, char** argv) {
  tcmalloc::TestingPortal::Get()->GetSampleParameter() = 512 << 10;
  // Make sure allocations we sample are done on fresh thread cache, so that
  // sampling parameter update is taken into account.
  MallocExtension::instance()->MarkThreadIdle();

  for (int i = 0; i < 8000; i++) {
    AllocateAllocate();
  }

  TempFile heap_tmp = TempFile::Create("sampling_test.heap.XXXXXX");
  TempFile growth_tmp = TempFile::Create("sampling_test.growth.XXXXXX");
  tcmalloc::Cleanup unlink_temps{[&] () {
    (void)unlink(heap_tmp.path.c_str());
    (void)unlink(growth_tmp.path.c_str());
  }};

  std::string s;
  MallocExtension::instance()->GetHeapSample(&s);
  fwrite(s.data(), 1, s.size(), heap_tmp.f);
  fclose(heap_tmp.ReleaseFile());

  s.clear();
  MallocExtension::instance()->GetHeapGrowthStacks(&s);
  fwrite(s.data(), 1, s.size(), growth_tmp.f);
  fclose(growth_tmp.ReleaseFile());

  VerifyWithPProf(argv[0], heap_tmp.path);
  VerifyWithPProf(argv[0], growth_tmp.path);
}
gperftools-gperftools-2.18/src/tests/stack_trace_table_test.cc000066400000000000000000000050771513545575200247700ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright 2009 Google Inc. All Rights Reserved.
// Author: fikes@google.com (Andrew Fikes)
//
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.


#include "config_for_unittests.h"

#include "stack_trace_table.h"

#include "gtest/gtest.h"

class StackTraceTableTestHelper {
public:
  using StackTrace = tcmalloc::StackTrace;

  struct Entry {
    const StackTrace trace;
    std::unique_ptr next{};
    Entry(const StackTrace& t) : trace(t) {}
  };
  using EntryPtr = std::unique_ptr;

  void AddTrace(const StackTrace& t) {
    EntryPtr e{new Entry{t}};
    head_.swap(e->next);
    head_.swap(e);
  }

  std::unique_ptr DumpTraces() {
    auto retval = ProduceStackTracesDump(
      +[] (const void** current_head) {
        const Entry* head = static_cast(*current_head);
        *current_head = head->next.get();
        return &head->trace;
      }, head_.get());

    head_.reset();
    return retval;
  }

  void CheckTracesAndReset(const uintptr_t* expected, int len) {
    std::unique_ptr entries = DumpTraces();
    for (int i = 0; i < len; i++) {
      EXPECT_EQ(reinterpret_cast(entries[i]), expected[i]);
    }
  }
private:
  EntryPtr head_;
};

TEST(StackTraceTableTest, Basic) {
  StackTraceTableTestHelper h;

  // Empty table
  static const uintptr_t k1[] = {0};
  h.CheckTracesAndReset(k1, arraysize(k1));

  tcmalloc::StackTrace t1;
  t1.size = static_cast(1024);
  t1.depth = static_cast(2);
  t1.stack[0] = reinterpret_cast(1);
  t1.stack[1] = reinterpret_cast(2);

  tcmalloc::StackTrace t2;
  t2.size = static_cast(512);
  t2.depth = static_cast(2);
  t2.stack[0] = reinterpret_cast(2);
  t2.stack[1] = reinterpret_cast(1);

  // Table w/ just t1
  h.AddTrace(t1);
  static const uintptr_t k2[] = {1, 1024, 2, 1, 2, 0};
  h.CheckTracesAndReset(k2, arraysize(k2));

  // Table w/ t1, t2
  h.AddTrace(t1);
  h.AddTrace(t2);
  static const uintptr_t k3[] = {1, 512, 2, 2, 1, 1, 1024, 2, 1, 2, 0};
  h.CheckTracesAndReset(k3, arraysize(k3));

  // Table w/ t1, t3
  // Same stack as t1, but w/ different size
  tcmalloc::StackTrace t3;
  t3.size = static_cast(2);
  t3.depth = static_cast(2);
  t3.stack[0] = reinterpret_cast(1);
  t3.stack[1] = reinterpret_cast(2);

  h.AddTrace(t1);
  h.AddTrace(t3);
  static const uintptr_t k5[] = {1, 2, 2, 1, 2, 1, 1024, 2, 1, 2, 0};
  h.CheckTracesAndReset(k5, arraysize(k5));
}
gperftools-gperftools-2.18/src/tests/stacktrace_unittest.cc000066400000000000000000000332641513545575200243610ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "config_for_unittests.h"
#ifdef HAVE_EXECINFO_H
#include 
#endif
#include 
#include 

// Correctly capturing backtrace from signal handler is most
// brittle. A number of configurations on Linux work, but not
// all. Same applies to BSDs. But lets somewhat broadly ask those
// setups to be tested. In general, if right backtraces are needed for
// CPU profiler, this test should pass as well.
#if __linux__ || (__FreeBSD__ && (__x86_64__ || __i386__)) || __NetBSD__
#include 
#include 
#define TEST_UCONTEXT_BITS 1
#endif

#if defined(__has_feature)
#  if __has_feature(address_sanitizer)
#undef TEST_UCONTEXT_BITS
#  endif
#endif

#include 

#include "base/logging.h"
#include 

// Obtain a backtrace, verify that the expected callers are present in the
// backtrace, and maybe print the backtrace to stdout.

// The sequence of functions whose return addresses we expect to see in the
// backtrace.
const int BACKTRACE_STEPS = 6;

static const char* tested_implementation_name;

struct AddressRange {
  const void *start, *end;
};

// Expected function [start,end] range.
AddressRange expected_range[BACKTRACE_STEPS];

bool skipping_ucontext;

#if __GNUC__
// Using GCC extension: address of a label can be taken with '&&label'.
// Start should be a label somewhere before recursive call, end somewhere
// after it.
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange)           \
  do {                                                                   \
    (prange)->start = &&start_label;                                     \
    (prange)->end = &&end_label;                                         \
    CHECK_LT((prange)->start, (prange)->end);                            \
  } while (0)
// This macro expands into "unmovable" code (opaque to GCC), and that
// prevents GCC from moving a_label up or down in the code.
// Without it, there is no code following the 'end' label, and GCC
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
// the recursive call.
#define DECLARE_ADDRESS_LABEL(a_label)                                   \
  a_label: do { __asm__ __volatile__(""); } while (0)
// Gcc 4.4.0 may split function into multiple chunks, and the chunk
// performing recursive call may end up later in the code then the return
// instruction (this actually happens with FDO).
// Adjust function range from __builtin_return_address.
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange)                             \
  do {                                                                   \
    void *ra = __builtin_return_address(0);                              \
    CHECK_LT((prange)->start, ra);                                       \
    if (ra > (prange)->end) {                                            \
      printf("Adjusting range from %p..%p to %p..%p\n",                  \
             (prange)->start, (prange)->end,                             \
             (prange)->start, ra);                                       \
      (prange)->end = ra;                                                \
    }                                                                    \
  } while (0)
#else
// Assume the Check* functions below are not longer than 256 bytes.
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange)           \
  do {                                                                   \
    (prange)->start = reinterpret_cast(&fn);               \
    (prange)->end = reinterpret_cast(&fn) + 256;           \
  } while (0)
#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
#endif  // __GNUC__


//-----------------------------------------------------------------------//

void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
{
  CHECK_GE(ret_addr, range.start);
  CHECK_LE(ret_addr, range.end);
}

//-----------------------------------------------------------------------//

extern "C" {

#if TEST_UCONTEXT_BITS

struct get_stack_trace_args {
  volatile bool ready;
  volatile bool captured;

  int *size_ptr;
  void **result;
  int max_depth;
} gst_args;

static
void SignalHandler(int dummy, siginfo_t *si, void* ucv) {
  if (!gst_args.ready || gst_args.captured) {
    return;
  }

  gst_args.captured = true;

  auto uc = static_cast(ucv);

  *gst_args.size_ptr = GetStackTraceWithContext(gst_args.result,
                                                gst_args.max_depth,
                                                2,
                                                uc);
}

int ATTRIBUTE_NOINLINE CaptureLeafUContext(void **stack, int stack_len) {
  INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
  DECLARE_ADDRESS_LABEL(start);

  int size;

  printf("Capturing stack trace from signal's ucontext\n");
  struct sigaction sa;
  struct sigaction old_sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_sigaction = SignalHandler;
  sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
  int rv = sigaction(SIGPROF, &sa, &old_sa);
  CHECK(rv == 0);

  gst_args.size_ptr = &size;
  gst_args.result = stack;
  gst_args.max_depth = stack_len;
  gst_args.captured = false;
  gst_args.ready = false;

  struct itimerval it;
  it.it_interval.tv_sec = 0;
  it.it_interval.tv_usec = 0;
  it.it_value.tv_sec = 0;
  it.it_value.tv_usec = 1;

  rv = setitimer(ITIMER_PROF, &it, nullptr);
  CHECK(rv == 0);

  // SignalHandler will run somewhere here, making sure we capture
  // backtrace from signal handler
  gst_args.ready = true;
  while (!gst_args.captured) {
    // do nothing
  }

  rv = sigaction(SIGPROF, &old_sa, nullptr);
  CHECK(rv == 0);

  printf("Obtained %d stack frames.\n", size);
  CHECK_GE(size, 1);
  CHECK_LE(size, stack_len);

  DECLARE_ADDRESS_LABEL(end);

  return size;
}

#endif  // TEST_UCONTEXT_BITS

int ATTRIBUTE_NOINLINE CaptureLeafPlain(void **stack, int stack_len) {
  INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
  DECLARE_ADDRESS_LABEL(start);

  int size = GetStackTrace(stack, stack_len, 0);

  printf("Obtained %d stack frames.\n", size);
  CHECK_GE(size, 1);
  CHECK_LE(size, stack_len);

  DECLARE_ADDRESS_LABEL(end);

  return size;
}

int ATTRIBUTE_NOINLINE CaptureLeafPlainEmptyUCP(void **stack, int stack_len) {
  INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
  DECLARE_ADDRESS_LABEL(start);

  int size = GetStackTraceWithContext(stack, stack_len, 0, nullptr);

  printf("Obtained %d stack frames.\n", size);
  CHECK_GE(size, 1);
  CHECK_LE(size, stack_len);

  DECLARE_ADDRESS_LABEL(end);

  return size;
}

int ATTRIBUTE_NOINLINE CaptureLeafWSkip(void **stack, int stack_len) {
  INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
  DECLARE_ADDRESS_LABEL(start);

  auto trampoline = [] (void **stack, int stack_len) ATTRIBUTE_NOINLINE {
    int rv = GetStackTrace(stack, stack_len, 1);
    (void)*(void * volatile *)(stack); // prevent tail-calling GetStackTrace
    return rv;
  };

  int size;

  // Lets ensure size skip_count > frames_available case is sensible
  // as well.
  size = GetStackTrace(stack, stack_len, 10240);
  CHECK_EQ(size, 0);

  size = trampoline(stack, stack_len);

  printf("Obtained %d stack frames.\n", size);
  CHECK_GE(size, 1);
  CHECK_LE(size, stack_len);

  DECLARE_ADDRESS_LABEL(end);

  return size;
}

void ATTRIBUTE_NOINLINE CheckStackTrace(int);

int (*leaf_capture_fn)(void**, int);
int leaf_capture_len;

void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(int i) {
  std::vector stack(leaf_capture_len + 1);
  stack[leaf_capture_len] = (void*)0x42;  // we will check that this value is not overwritten
  int size = 0;

  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);

  size = leaf_capture_fn(stack.data(), leaf_capture_len);
  CHECK_EQ(stack[leaf_capture_len], (void*)0x42);

#ifdef HAVE_EXECINFO_H
  {
    char **strings = backtrace_symbols(stack.data(), size);
    for (int i = 0; i < size; i++)
      printf("%s %p\n", strings[i], stack[i]);
    printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
    free(strings);
  }
#endif

  for (int i = 0, j = 0; i < BACKTRACE_STEPS && j < size; i++, j++) {
    if (i == 1 && j == 1) {
      // this is expected to be our function for which we don't
      // establish bounds. So skip.
      i--;
      continue;
    }
    printf("Backtrace %d: expected: %p..%p  actual: %p ... ",
           i, expected_range[i].start, expected_range[i].end, stack[j]);
    fflush(stdout);
    CheckRetAddrIsInFunction(stack[j], expected_range[i]);
    printf("OK\n");
  }
}

//-----------------------------------------------------------------------//

/* Dummy functions to make the backtrace more interesting. */
void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
  INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
  DECLARE_ADDRESS_LABEL(start);
  for (int j = i; j >= 0; j--)
    CheckStackTraceLeaf(j);
  DECLARE_ADDRESS_LABEL(end);
}
void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
  INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
  DECLARE_ADDRESS_LABEL(start);
  for (int j = i; j >= 0; j--)
    CheckStackTrace4(j);
  DECLARE_ADDRESS_LABEL(end);
}
void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
  INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
  DECLARE_ADDRESS_LABEL(start);
  for (int j = i; j >= 0; j--)
    CheckStackTrace3(j);
  DECLARE_ADDRESS_LABEL(end);
}
void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
  INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
  DECLARE_ADDRESS_LABEL(start);
  for (int j = i; j >= 0; j--)
    CheckStackTrace2(j);
  DECLARE_ADDRESS_LABEL(end);
}
void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
  INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
  DECLARE_ADDRESS_LABEL(start);
  for (int j = i; j >= 0; j--) {
    CheckStackTrace1(j);
  }
  DECLARE_ADDRESS_LABEL(end);
}

}  // extern "C"

static void RunStackTraceCheck(int (*bt_capture_fn)(void**, int)) {
  leaf_capture_fn = bt_capture_fn;
  CheckStackTrace(0);
}

void RunTest(int capture_depth) {
  leaf_capture_len = capture_depth;

  RunStackTraceCheck(CaptureLeafPlain);
  printf("PASS\n");

  printf("Will test capturing stack trace with nullptr ucontext\n");
  RunStackTraceCheck(CaptureLeafPlainEmptyUCP);
  printf("PASS\n");

  printf("Will test capturing stack trace with skipped frames\n");
  RunStackTraceCheck(CaptureLeafWSkip);
  printf("PASS\n");

#if TEST_UCONTEXT_BITS
  bool want_to_test = !skipping_ucontext;
#if !__linux__ || !defined(__GLIBC__)
  // Our current "with ucontext" backtracing relies on fixed number of
  // stack frames to skip. Which is brittle and actually fails on
  // e.g. BSDs. There is a notable exception of generic_fp
  // backtracer. Which, if exists, is actually doing backtracing from
  // given ucontext parameter. So on Linux we test all implementations
  // (which passes in practice at least on platforms I test), and
  // everyone else only does ucontext tests with generic_fp method.
  std::string name = tested_implementation_name;
  want_to_test = want_to_test && (name == "generic_fp" || name == "generic_fp_unsafe");
#endif  // !__linux__
  if (want_to_test) {
    RunStackTraceCheck(CaptureLeafUContext);
    printf("PASS\n");
  }
#endif  // TEST_UCONTEXT_BITS
}

extern "C" {
const char* TEST_bump_stacktrace_implementation(const char*);
}

int main(int argc, char** argv) {
  if (argc > 1 && strcmp(argv[1], "--skip-ucontext") == 0) {
    argc--;
    argv--;
    skipping_ucontext = true;
  }

  for (;;) {
    // first arg if given is stacktrace implementation we want to test
    tested_implementation_name = TEST_bump_stacktrace_implementation((argc > 1) ? argv[1] : nullptr);
    if (!tested_implementation_name) {
      break;
    }
    printf("\n-----\nTesting stacktrace implementation: %s\n", tested_implementation_name);

    RunTest(20);

    printf("\nSet max capture length to 3:\n");
    RunTest(3); // depth of 3 is less than space we have for stacktrace
  }

  return 0;
}
gperftools-gperftools-2.18/src/tests/system-alloc_unittest.cc000066400000000000000000000076341513545575200246530ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Arun Sharma
#include "config_for_unittests.h"

#include "gperftools/malloc_extension.h"

#include 
#include 
#include 

#include 

#include "base/cleanup.h"
#include "tests/testutil.h"

#include "gtest/gtest.h"

class TestSysAllocator : public SysAllocator {
public:
  // Was this allocator invoked at least once?
  bool invoked_ = false;

  TestSysAllocator(SysAllocator* prev) : SysAllocator(), prev_(prev) {}
  ~TestSysAllocator() override {}

  void* Alloc(size_t size, size_t *actual_size, size_t alignment) override {
    invoked_ = true;
    return prev_->Alloc(size, actual_size, alignment);
  }
private:
  SysAllocator* const prev_;
};

TEST(SystemAllocTest, GetsInvoked) {
  SysAllocator* prev = MallocExtension::instance()->GetSystemAllocator();
  tcmalloc::Cleanup restore_sys_allocator([prev] () {
    MallocExtension::instance()->SetSystemAllocator(prev);
  });

  // Note, normally SysAllocator instances cannot be destroyed, but
  // we're single-threaded isolated unit test. And we know what we're
  // doing.
  TestSysAllocator test_allocator{prev};
  MallocExtension::instance()->SetSystemAllocator(&test_allocator);

  // An allocation size that is likely to trigger the system allocator.
  char *p =  noopt(new char[20 << 20]);
  delete [] p;

  // Make sure that our allocator was invoked.
  ASSERT_TRUE(test_allocator.invoked_);
}

TEST(SystemAllocTest, RetryAfterFail) {
  // Check with the allocator still works after a failed allocation.
  //
  // There is no way to call malloc and guarantee it will fail.  malloc takes a
  // size_t parameter and the C++ standard does not constrain the size of
  // size_t.  For example, consider an implementation where size_t is 32 bits
  // and pointers are 64 bits.
  //
  // It is likely, though, that sizeof(size_t) == sizeof(void*).  In that case,
  // the first allocation here might succeed but the second allocation must
  // fail.
  //
  // If the second allocation succeeds, you will have to rewrite or
  // disable this test.
  // The weird parens are to avoid macro-expansion of 'max' on windows.
  constexpr size_t kHugeSize = std::numeric_limits::max() / 2;
  void* p1 = noopt(malloc(kHugeSize));
  void* p2 = noopt(malloc(kHugeSize));
  ASSERT_EQ(p2, nullptr);

  free(p1);

  char* q = noopt(new char[1024]);
  delete [] q;
}
gperftools-gperftools-2.18/src/tests/tcmalloc_large_unittest.cc000066400000000000000000000112271513545575200252000ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Michael Chastain
//
// This is a unit test for large allocations in malloc and friends.
// "Large" means "so large that they overflow the address space".
// For 32 bits, this means allocations near 2^32 bytes and 2^31 bytes.
// For 64 bits, this means allocations near 2^64 bytes and 2^63 bytes.

#include                      // for size_t
#include                      // for malloc, free, realloc
#include 
#include                           // for set, etc

#include "base/logging.h"               // for operator<<, CHECK, etc
#include "tests/testutil.h"

using std::set;

// Alloc a size that should always fail.

void TryAllocExpectFail(size_t size) {
  void* p1 = noopt(malloc)(size);
  CHECK(p1 == nullptr);

  void* p2 = noopt(malloc)(1);
  CHECK(p2 != nullptr);

  void* p3 = noopt(realloc)(p2, size);
  CHECK(p3 == nullptr);

  free(p2);
}

// Alloc a size that might work and might fail.
// If it does work, touch some pages.

void TryAllocMightFail(size_t size) {
  unsigned char* p = static_cast(noopt(malloc)(size));
  if (p != nullptr) {
    static const size_t kPoints = 1024;

    for ( size_t i = 0; i < kPoints; ++i ) {
      p[i * (size / kPoints)] = static_cast(i);
    }

    for ( size_t i = 0; i < kPoints; ++i ) {
      CHECK(p[i * (size / kPoints)] == static_cast(i));
    }

    p[size-1] = 'M';
    CHECK(p[size-1] == 'M');
  }

  free(noopt(p));
}

int main (int argc, char** argv) {
  // Allocate some 0-byte objects.  They better be unique.
  // 0 bytes is not large but it exercises some paths related to
  // large-allocation code.
  {
    static const int kZeroTimes = 1024;
    printf("Test malloc(0) x %d\n", kZeroTimes);
    set p_set;
    for ( int i = 0; i < kZeroTimes; ++i ) {
      char* p = new char;
      CHECK(p != nullptr);
      CHECK(p_set.find(p) == p_set.end());
      p_set.insert(p_set.end(), p);
    }
    // Just leak the memory.
  }

  // Grab some memory so that some later allocations are guaranteed to fail.
  printf("Test small malloc\n");
  void* p_small = noopt(malloc(4*1048576));
  CHECK(p_small != nullptr);

  // Test sizes up near the maximum size_t.
  // These allocations test the wrap-around code.
  printf("Test malloc(0 - N)\n");
  const size_t zero = 0;
  static const size_t kMinusNTimes = 16384;
  for ( size_t i = 1; i < kMinusNTimes; ++i ) {
    TryAllocExpectFail(zero - i);
  }

  // Test sizes a bit smaller.
  // The small malloc above guarantees that all these return nullptr.
  printf("Test malloc(0 - 1048576 - N)\n");
  static const size_t kMinusMBMinusNTimes = 16384;
  for ( size_t i = 0; i < kMinusMBMinusNTimes; ++i) {
    TryAllocExpectFail(zero - 1048576 - i);
  }

  // Test sizes at half of size_t.
  // These might or might not fail to allocate.
  printf("Test malloc(max/2 +- N)\n");
  static const size_t kHalfPlusMinusTimes = 64;
  const size_t half = (zero - 2) / 2 + 1;
  for ( size_t i = 0; i < kHalfPlusMinusTimes; ++i) {
    TryAllocMightFail(half - i);
    TryAllocMightFail(half + i);
  }

  printf("PASS\n");
  return 0;
}
gperftools-gperftools-2.18/src/tests/tcmalloc_unittest.cc000066400000000000000000002225761513545575200240410ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Unittest for the TCMalloc implementation.
//
// * The test consists of a set of threads.
// * Each thread maintains a set of allocated objects, with
//   a bound on the total amount of data in the set.
// * Each allocated object's contents are generated by
//   hashing the object pointer, and a generation count
//   in the object.  This allows us to easily check for
//   data corruption.
// * At any given step, the thread can do any of the following:
//     a. Allocate an object
//     b. Increment an object's generation count and update
//        its contents.
//     c. Pass the object to another thread
//     d. Free an object
//   Also, at the end of every step, object(s) are freed to maintain
//   the memory upper-bound.
//
#include "config_for_unittests.h"
// Complicated ordering requirements.  tcmalloc.h defines (indirectly)
// _POSIX_C_SOURCE, which it needs so stdlib.h defines posix_memalign.
// unistd.h, on the other hand, requires _POSIX_C_SOURCE to be unset,
// at least on FreeBSD, in order to define sbrk.  The solution
// is to #include unistd.h first.  This is safe because unistd.h
// doesn't sub-include stdlib.h, so we'll still get posix_memalign
// when we #include stdlib.h.  Blah.
#ifdef HAVE_UNISTD_H
#include                  // for testing sbrk hooks
#endif
#include "tcmalloc_internal.h"      // must come early, to pick up posix_memalign
#include 
#include 
#include 
#include                  // for intptr_t
#include               // for size_t
#ifdef HAVE_FCNTL_H
#include                   // for open; used with mmap-hook test
#endif
#ifdef HAVE_MALLOC_H
#include                  // defines pvalloc/etc on cygwin
#endif
#include 

#ifndef _WIN32
#include  // for posix_spawn
#include  // for waitpid
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#if __linux__ && __x86_64__
// for fork testing
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define HAVE_FORK_TESTING_SUPPORT
#endif // __linux__ && __x86_64__

#include "gperftools/malloc_hook.h"
#include "gperftools/malloc_extension.h"
#include "gperftools/nallocx.h"
#include "gperftools/tcmalloc.h"

#include "base/environ.h"
#include "base/cleanup.h"
#include "base/function_ref.h"
#include "base/logging.h"
#include "base/static_storage.h"

#include "tests/testutil.h"

#include "testing_portal.h"

#include "gtest/gtest.h"



static bool running_fork_testing;

using tcmalloc::TestingPortal;

namespace {

// SetFlag updates given variable to new value and returns
// tcmalloc::Cleanup that restores it to previous value.
template 
decltype(auto) SetFlag(T* ptr, V value) {
  T old_value = *ptr;
  *ptr = value;
  return tcmalloc::Cleanup{[=] () {
    *ptr = old_value;
  }};
}

struct NumericProperty {
  const char* const name;

  constexpr NumericProperty(const char* name) : name(name) {}

  // Override sets this property to new value and returns
  // tcmalloc::Cleanup that returns it to previous setting.
  decltype(auto) Override(size_t new_value) const {
    MallocExtension *e = MallocExtension::instance();
    size_t old_value;

    CHECK(e->GetNumericProperty(name, &old_value));
    CHECK(e->SetNumericProperty(name, new_value));

    return tcmalloc::Cleanup{[old_value, name = name] () {
      CHECK(MallocExtension::instance()->SetNumericProperty(name, old_value));
    }};
  }
};

constexpr NumericProperty kAggressiveDecommit{"tcmalloc.aggressive_memory_decommit"};

}  // namespace

// Windows doesn't define pvalloc and a few other obsolete unix
// functions; nor does it define posix_memalign (which is not obsolete).
#if defined(_WIN32)
# define valloc malloc
# define pvalloc malloc
// I'd like to map posix_memalign to _aligned_malloc, but _aligned_malloc
// must be paired with _aligned_free (not normal free), which is too
// invasive a change to how we allocate memory here.  So just bail
static bool kOSSupportsMemalign = false;
static inline void* Memalign(size_t align, size_t size) {
  //LOG(FATAL) << "memalign not supported on windows";
  exit(1);
  return nullptr;
}
static inline int PosixMemalign(void** ptr, size_t align, size_t size) {
  //LOG(FATAL) << "posix_memalign not supported on windows";
  exit(1);
  return -1;
}

// OS X defines posix_memalign in some OS versions but not others;
// it's confusing enough to check that it's easiest to just not to test.
#elif defined(__APPLE__)
static bool kOSSupportsMemalign = false;
static inline void* Memalign(size_t align, size_t size) {
  //LOG(FATAL) << "memalign not supported on OS X";
  exit(1);
  return nullptr;
}
static inline int PosixMemalign(void** ptr, size_t align, size_t size) {
  //LOG(FATAL) << "posix_memalign not supported on OS X";
  exit(1);
  return -1;
}

#else
static bool kOSSupportsMemalign = true;
static inline void* Memalign(size_t align, size_t size) {
  return noopt(memalign(align, noopt(size)));
}
static inline int PosixMemalign(void** ptr, size_t align, size_t size) {
  return noopt(posix_memalign(ptr, align, noopt(size)));
}

#endif

static constexpr size_t kOveralignment = 64;

struct overaligned_type
{
  alignas(kOveralignment)
  unsigned char data[kOveralignment * 2]; // make the object size different from
                                          // alignment to make sure the correct
                                          // values are passed to the new/delete
                                          // implementation functions
};

struct OOMAbleSysAlloc : public SysAllocator {
  SysAllocator *child;
  int simulate_oom;

  void* Alloc(size_t size, size_t* actual_size, size_t alignment) {
    if (simulate_oom) {
      return nullptr;
    }
    return child->Alloc(size, actual_size, alignment);
  }
};

static OOMAbleSysAlloc* get_test_sys_alloc() {
  static tcmalloc::StaticStorage storage;
  return storage.get();
}

void setup_oomable_sys_alloc() {
  SysAllocator *def = MallocExtension::instance()->GetSystemAllocator();

  OOMAbleSysAlloc *alloc = get_test_sys_alloc();
  new (alloc) OOMAbleSysAlloc;
  alloc->child = def;

  MallocExtension::instance()->SetSystemAllocator(alloc);
}

static const int FLAGS_numtests = 50000;
static const int FLAGS_log_every_n_tests = 50000; // log exactly once

// Testing parameters
static const int FLAGS_lgmaxsize = 16;   // lg() of the max size object to alloc
static const int FLAGS_numthreads = 10;  // Number of threads
static const int FLAGS_threadmb = 4;     // Max memory size allocated by thread
static const int FLAGS_lg_max_memalign = 18; // lg of max alignment for memalign

static const double FLAGS_memalign_min_fraction = 0;    // min expected%
static const double FLAGS_memalign_max_fraction = 0.4;  // max expected%
static const double FLAGS_memalign_max_alignment_ratio = 6;  // alignment/size

// Weights of different operations
static const int FLAGS_allocweight = 50;    // Weight for picking allocation
static const int FLAGS_freeweight = 50;     // Weight for picking free
static const int FLAGS_updateweight = 10;   // Weight for picking update
static const int FLAGS_passweight = 1;      // Weight for passing object

static const int kSizeBits = 8 * sizeof(size_t);
static const size_t kMaxSize = ~static_cast(0);
static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);

static const size_t kNotTooBig = 100000;
// We want an allocation that is definitely more than main memory.  OS
// X has special logic to discard very big allocs before even passing
// the request along to the user-defined memory allocator; we're not
// interested in testing their logic, so we have to make sure we're
// not *too* big.
static const size_t kTooBig = kMaxSize - 100000;

// To help with generating random numbers
class TestHarness {
 private:
  // Information kept per type
  struct Type {
    std::string name;
    int         type;
    int         weight;
  };

 public:
  TestHarness(int seed) {
    srandom(seed);
  }

  // Add operation type with specified weight.  When starting a new
  // iteration, an operation type is picked with probability
  // proportional to its weight.
  //
  // "type" must be non-negative.
  // "weight" must be non-negative.
  void AddType(int type, int weight, const char* name);

  // Call this to get the type of operation for the next iteration.
  // It returns a random operation type from the set of registered
  // operations.  Returns -1 if tests should finish.
  int PickType();

  // If n == 0, returns the next pseudo-random number in the range [0 .. 0]
  // If n != 0, returns the next pseudo-random number in the range [0 .. n)
  int Uniform(int n) {
    if (n == 0) {
      return random() * 0;
    } else {
      return random() % n;
    }
  }
  // Pick "base" uniformly from range [0,max_log] and then return
  // "base" random bits.  The effect is to pick a number in the range
  // [0,2^max_log-1] with bias towards smaller numbers.
  int Skewed(int max_log) {
    const int base = random() % (max_log+1);
    return random() % (1 << base);
  }

 private:
  std::vector     types_;             // Registered types
  int                   total_weight_ = 0;  // Total weight of all types
  int                   num_tests_ = 0;     // Num tests run so far
};

void TestHarness::AddType(int type, int weight, const char* name) {
  Type t;
  t.name = name;
  t.type = type;
  t.weight = weight;
  types_.push_back(t);
  total_weight_ += weight;
}

int TestHarness::PickType() {
  if (num_tests_ >= FLAGS_numtests) return -1;
  num_tests_++;

  CHECK(total_weight_ > 0);
  // This is a little skewed if total_weight_ doesn't divide 2^31, but it's close
  int v = Uniform(total_weight_);
  int i;
  for (i = 0; i < types_.size(); i++) {
    v -= types_[i].weight;
    if (v < 0) {
      break;
    }
  }

  CHECK(i < types_.size());
  if ((num_tests_ % FLAGS_log_every_n_tests) == 0) {
    printf("  Test %d out of %d: %s\n",
            num_tests_, FLAGS_numtests, types_[i].name.c_str());
  }
  return types_[i].type;
}

class AllocatorState : public TestHarness {
 public:
  explicit AllocatorState(int seed) : TestHarness(seed), memalign_fraction_(0) {
    if (kOSSupportsMemalign) {
      CHECK_GE(FLAGS_memalign_max_fraction, 0);
      CHECK_LE(FLAGS_memalign_max_fraction, 1);
      CHECK_GE(FLAGS_memalign_min_fraction, 0);
      CHECK_LE(FLAGS_memalign_min_fraction, 1);
      double delta = FLAGS_memalign_max_fraction - FLAGS_memalign_min_fraction;
      CHECK_GE(delta, 0);
      memalign_fraction_ = (Uniform(10000)/10000.0 * delta +
                            FLAGS_memalign_min_fraction);
      //printf("memalign fraction: %f\n", memalign_fraction_);
    }
  }
  virtual ~AllocatorState() {}

  // Allocate memory.  Randomly choose between malloc() or posix_memalign().
  void* alloc(size_t size) {
    if (Uniform(100) < memalign_fraction_ * 100) {
      // Try a few times to find a reasonable alignment, or fall back on malloc.
      for (int i = 0; i < 5; i++) {
        size_t alignment = size_t{1} << Uniform(FLAGS_lg_max_memalign);
        if (alignment >= sizeof(intptr_t) &&
            (size < sizeof(intptr_t) ||
             alignment < FLAGS_memalign_max_alignment_ratio * size)) {
          void *result = reinterpret_cast(static_cast(0x1234));
          int err = PosixMemalign(&result, alignment, size);
          if (err != 0) {
            CHECK_EQ(err, ENOMEM);
          }
          return err == 0 ? result : nullptr;
        }
      }
    }
    return noopt(malloc(size));
  }

 private:
  double memalign_fraction_;
};


// Info kept per thread
class TesterThread {
 private:
  // Info kept per allocated object
  struct Object {
    char*       ptr;                    // Allocated pointer
    int         size;                   // Allocated size
    int         generation;             // Generation counter of object contents
  };

  std::vector> &all_threads_;

  std::mutex            lock_;          // For passing in another thread's obj
  int                   id_;            // My thread id
  AllocatorState        rnd_;           // For generating random numbers
  std::vector   heap_;          // This thread's heap
  std::vector   passed_;        // Pending objects passed from others
  size_t                heap_size_;     // Current heap size

  // Type of operations
  enum Type { ALLOC, FREE, UPDATE, PASS };

  // ACM minimal standard random number generator.  (re-entrant.)
  class ACMRandom {
    int32_t seed_;
   public:
    explicit ACMRandom(int32_t seed) { seed_ = seed; }
    int32_t Next() {
      const int32_t M = 2147483647L;   // 2^31-1
      const int32_t A = 16807;
      // In effect, we are computing seed_ = (seed_ * A) % M, where M = 2^31-1
      uint32_t lo = A * (int32_t)(seed_ & 0xFFFF);
      uint32_t hi = A * (int32_t)((uint32_t)seed_ >> 16);
      lo += (hi & 0x7FFF) << 16;
      if (lo > M) {
        lo &= M;
        ++lo;
      }
      lo += hi >> 15;
      if (lo > M) {
        lo &= M;
        ++lo;
      }
      return (seed_ = (int32_t) lo);
    }
  };

 public:
  TesterThread(std::vector>& all_threads, int id)
    : all_threads_(all_threads),
      id_(id),
      rnd_(id+1),
      heap_size_(0) {
  }

  virtual ~TesterThread() {
  }

  virtual void Run() {
    rnd_.AddType(ALLOC,  FLAGS_allocweight,   "allocate");
    rnd_.AddType(FREE,   FLAGS_freeweight,    "free");
    rnd_.AddType(UPDATE, FLAGS_updateweight,  "update");
    rnd_.AddType(PASS,   FLAGS_passweight,    "pass");

    while (true) {
      AcquirePassedObjects();

      switch (rnd_.PickType()) {
        case ALLOC:   AllocateObject(); break;
        case FREE:    FreeObject();     break;
        case UPDATE:  UpdateObject();   break;
        case PASS:    PassObject();     break;
        case -1:      goto done;
        default:      CHECK(nullptr == "Unknown type");
      }

      ShrinkHeap();
    }

 done:
    DeleteHeap();
  }

  // Allocate a new object
  void AllocateObject() {
    Object object;
    object.size = rnd_.Skewed(FLAGS_lgmaxsize);
    object.ptr = static_cast(rnd_.alloc(object.size));
    CHECK(object.ptr);
    object.generation = 0;
    FillContents(&object);
    heap_.push_back(object);
    heap_size_ += object.size;
  }

  // Mutate a random object
  void UpdateObject() {
    if (heap_.empty()) return;
    const int index = rnd_.Uniform(heap_.size());
    CheckContents(heap_[index]);
    heap_[index].generation++;
    FillContents(&heap_[index]);
  }

  // Free a random object
  void FreeObject() {
    if (heap_.empty()) return;
    const int index = rnd_.Uniform(heap_.size());
    Object object = heap_[index];
    CheckContents(object);
    free(object.ptr);
    heap_size_ -= object.size;
    heap_[index] = heap_[heap_.size()-1];
    heap_.pop_back();
  }

  // Delete all objects in the heap
  void DeleteHeap() {
    while (!heap_.empty()) {
      FreeObject();
    }
  }

  // Free objects until our heap is small enough
  void ShrinkHeap() {
    while (heap_size_ > FLAGS_threadmb << 20) {
      CHECK(!heap_.empty());
      FreeObject();
    }
  }

  // Pass a random object to another thread
  void PassObject() {
    // Pick object to pass
    if (heap_.empty()) return;
    const int index = rnd_.Uniform(heap_.size());
    Object object = heap_[index];
    CheckContents(object);

    // Pick thread to pass
    const int tid = rnd_.Uniform(FLAGS_numthreads);
    TesterThread* thread = all_threads_[tid].get();

    if (thread->lock_.try_lock()) {
      // Pass the object
      thread->passed_.push_back(object);
      thread->lock_.unlock();
      heap_size_ -= object.size;
      heap_[index] = heap_[heap_.size()-1];
      heap_.pop_back();
    }
  }

  // Grab any objects passed to this thread by another thread
  void AcquirePassedObjects() {
    // We do not create unnecessary contention by always using
    // TryLock().  Plus we unlock immediately after swapping passed
    // objects into a local vector.
    std::vector copy;
    { // Locking scope
      if (!lock_.try_lock()) {
        return;
      }
      swap(copy, passed_);
      lock_.unlock();
    }

    for (int i = 0; i < copy.size(); ++i) {
      const Object& object = copy[i];
      CheckContents(object);
      heap_.push_back(object);
      heap_size_ += object.size;
    }
  }

  // Fill object contents according to ptr/generation
  void FillContents(Object* object) {
    ACMRandom r(reinterpret_cast(object->ptr) & 0x7fffffff);
    for (int i = 0; i < object->generation; ++i) {
      r.Next();
    }
    const char c = static_cast(r.Next());
    memset(object->ptr, c, object->size);
  }

  // Check object contents
  void CheckContents(const Object& object) {
    ACMRandom r(reinterpret_cast(object.ptr) & 0x7fffffff);
    for (int i = 0; i < object.generation; ++i) {
      r.Next();
    }

    // For large objects, we just check a prefix/suffix
    const char expected = static_cast(r.Next());
    const int limit1 = object.size < 32 ? object.size : 32;
    const int start2 = limit1 > object.size - 32 ? limit1 : object.size - 32;
    for (int i = 0; i < limit1; ++i) {
      CHECK_EQ(object.ptr[i], expected);
    }
    for (int i = start2; i < object.size; ++i) {
      CHECK_EQ(object.ptr[i], expected);
    }
  }
};

TEST(TCMallocTest, Versions) {
  auto build_version_string = [] (int major, int minor, const char* patch) -> std::string {
    CHECK(patch[0] == 0 || patch[0] == '.'); // patch version needs to start with dot
    std::stringstream ss;
    ss << "gperftools " << major << "." << minor << patch;
    return ss.str();
  };

  // We make sure that TC_VERSION_STRING define matches
  // TC_VERSION_MAJOR, TC_VERSION_MAJOR and TC_VERSION_PATCH (see
  // tcmalloc.h)
  std::string expected_version_string = build_version_string(TC_VERSION_MAJOR, TC_VERSION_MINOR, TC_VERSION_PATCH);
  ASSERT_EQ(expected_version_string, std::string(TC_VERSION_STRING));

  // autoconf's config.h has PACKAGE_VERSION that is taken from configure.ac
#if defined(PACKAGE_VERSION)
  // And we make sure that autoconf's idea of version matches what
  // we've manually put into tcmalloc.h
  ASSERT_EQ(expected_version_string, std::string("gperftools ") + PACKAGE_VERSION);
#else
  // Make sure we're able to exercise line above (we set this
  // environment variable in test runner)
  CHECK_EQ(getenv("GPERFTOOLS_ENSURE_PACKAGE_VERSION"), nullptr);
#endif
}

TEST(TCMallocTest, ManyThreads) {
  printf("Testing threaded allocation/deallocation (%d threads)\n",
          FLAGS_numthreads);

  std::vector> ptrs;
  ptrs.reserve(FLAGS_numthreads);
  // Note, the logic inside PassObject requires us to create all
  // TesterThreads first, before starting any of them.
  for (int i = 0; i < FLAGS_numthreads; i++) {
    ptrs.emplace_back(std::make_unique(ptrs, i));
  }

  std::vector threads;
  threads.reserve(FLAGS_numthreads);
  for (int i = 0; i < FLAGS_numthreads; i++) {
    threads.emplace_back([thr = ptrs[i].get()] () {
      thr->Run();
    });
  }
  for (auto& t : threads) {
    t.join();
  }
}

static void TryHugeAllocation(size_t s, AllocatorState* rnd) {
  void* p = rnd->alloc(noopt(s));
  CHECK(p == nullptr);   // huge allocation s should fail!
}

static void TestHugeAllocations(AllocatorState* rnd) {
  // Check that asking for stuff tiny bit smaller than largest possible
  // size returns nullptr.
  for (size_t i = 0; i < 70000; i += rnd->Uniform(20)) {
    TryHugeAllocation(kMaxSize - i, rnd);
  }
  // Asking for memory sizes near signed/unsigned boundary (kMaxSignedSize)
  // might work or not, depending on the amount of virtual memory.
  if (!TestingPortal::Get()->IsDebuggingMalloc()) {
   // debug allocation takes forever for huge allocs
    for (size_t i = 0; i < 100; i++) {
      void* p = nullptr;
      p = rnd->alloc(kMaxSignedSize + i);
      if (p) free(p);    // if: free(nullptr) is not necessarily defined
      p = rnd->alloc(kMaxSignedSize - i);
      if (p) free(p);
    }
  }

  // Check that ReleaseFreeMemory has no visible effect (aka, does not
  // crash the test):
  MallocExtension* inst = MallocExtension::instance();
  CHECK(inst);
  inst->ReleaseFreeMemory();
}

static void TestCalloc(size_t n, size_t s, bool ok) {
  char* p = reinterpret_cast(noopt(calloc)(n, s));
  if (!ok) {
    CHECK(p == nullptr);  // calloc(n, s) should not succeed
  } else {
    CHECK(p != nullptr);  // calloc(n, s) should succeed
    for (int i = 0; i < n*s; i++) {
      CHECK(p[i] == '\0');
    }
    free(p);
  }
}

// This makes sure that reallocing a small number of bytes in either
// direction doesn't cause us to allocate new memory.
class ReallocTest : public ::testing::TestWithParam {};

TEST_P(ReallocTest, Realloc) {
  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    // debug alloc doesn't try to minimize reallocs
    return;
  }
  // When sampling, we always allocate in units of page-size, which
  // makes reallocs of small sizes do extra work (thus, failing these
  // checks).  Since sampling is random, we turn off sampling to make
  // sure that doesn't happen to us here.

  // turn off sampling
  tcmalloc::Cleanup cleanup = SetFlag(&TestingPortal::Get()->GetSampleParameter(), 0);

  size_t original_size = GetParam();
  void* p = noopt(malloc(original_size));
  ASSERT_NE(p, nullptr);

  size_t usable_size = nallocx(original_size, 0);
  // Validate out expectation
  ASSERT_EQ(MallocExtension::instance()->GetAllocatedSize(p), usable_size);

  // Lets find range of request sizes that round up to the same
  // usable size by using nallocx.
  size_t minimal_size = original_size;
  while (nallocx(minimal_size - 1, 0) == usable_size) {
    minimal_size--;
    ASSERT_NE(minimal_size, 0);
  }

  void* new_p;

  // Check growing up to usable size then shrinking
  new_p = noopt(realloc)(p, usable_size);
  ASSERT_EQ(new_p, p);
  new_p = noopt(realloc)(p, minimal_size);
  ASSERT_EQ(new_p, p);

  // Checking shrinking then growing
  new_p = noopt(realloc)(p, minimal_size);
  ASSERT_EQ(new_p, p);
  new_p = noopt(realloc)(p, usable_size);
  ASSERT_EQ(new_p, p);

  free(p);
}

INSTANTIATE_TEST_SUITE_P(AllSizes, ReallocTest, ::testing::Values(100, 1000, 10000, 100000));

#if __cpp_exceptions
static int news_handled = 0;

static void TestNewHandler() {
  ++news_handled;
  throw std::bad_alloc();
}

static void TestOneNew(void* (*func)(size_t)) {
  func = noopt(func);
  // success test
  try {
    void* ptr = (*func)(kNotTooBig);
    if (0 == ptr) {
      printf("allocation should not have failed.\n");
      abort();
    }
  } catch (...) {
    printf("allocation threw unexpected exception.\n");
    abort();
  }

  // failure test
  // we should always receive a bad_alloc exception
  try {
    (*func)(kTooBig);
    printf("allocation should have failed.\n");
    abort();
  } catch (const std::bad_alloc&) {
    // correct
  } catch (...) {
    printf("allocation threw unexpected exception.\n");
    abort();
  }
}

static void TestNew(void* (*func)(size_t)) {
  news_handled = 0;

  // test without new_handler:
  std::new_handler saved_handler = std::set_new_handler(0);
  TestOneNew(func);

  // test with new_handler:
  std::set_new_handler(TestNewHandler);
  TestOneNew(func);
  if (news_handled != 1) {
    printf("new_handler was not called.\n");
    abort();
  }
  std::set_new_handler(saved_handler);
}

static void TestOneNothrowNew(void* (*func)(size_t, const std::nothrow_t&)) {
  func = noopt(func);
  // success test
  try {
    void* ptr = (*func)(kNotTooBig, std::nothrow);
    if (ptr == nullptr) {
      printf("allocation should not have failed.\n");
      abort();
    }
  } catch (...) {
    printf("allocation threw unexpected exception.\n");
    abort();
  }

  // failure test
  // we should always receive a bad_alloc exception
  try {
    if ((*func)(kTooBig, std::nothrow) != 0) {
      printf("allocation should have failed.\n");
      abort();
    }
  } catch (...) {
    printf("nothrow allocation threw unexpected exception.\n");
    abort();
  }
}

static void TestNothrowNew(void* (*func)(size_t, const std::nothrow_t&)) {
  news_handled = 0;

  // test without new_handler:
  std::new_handler saved_handler = std::set_new_handler(0);
  TestOneNothrowNew(func);

  // test with new_handler:
  std::set_new_handler(TestNewHandler);
  TestOneNothrowNew(func);
  if (news_handled != 1) {
    printf("nothrow new_handler was not called.\n");
    abort();
  }
  std::set_new_handler(saved_handler);
}

TEST(TCMallocTest, OperatorsNewOOMs) {
  printf("Testing operator new(nothrow).\n");
  TestNothrowNew(&::operator new);
  printf("Testing operator new[](nothrow).\n");
  TestNothrowNew(&::operator new[]);
  printf("Testing operator new.\n");
  TestNew(&::operator new);
  printf("Testing operator new[].\n");
  TestNew(&::operator new[]);
}

#endif  // __cpp_exceptions


// These are used as callbacks by the sanity-check.  Set* and Reset*
// register the hook that counts how many times the associated memory
// function is called.  After each such call, call Verify* to verify
// that we used the tcmalloc version of the call, and not the libc.
// Note the ... in the hook signature: we don't care what arguments
// the hook takes.
#define MAKE_HOOK_CALLBACK(hook_type, ...)                              \
  static volatile int g_##hook_type##_calls = 0;                                 \
  static void IncrementCallsTo##hook_type(__VA_ARGS__) {                \
    g_##hook_type##_calls++;                                            \
  }                                                                     \
  static void Verify##hook_type##WasCalled() {                          \
    CHECK_GT(g_##hook_type##_calls, 0);                                 \
    g_##hook_type##_calls = 0;  /* reset for next call */               \
  }                                                                     \
  static void Set##hook_type() {                                        \
    CHECK(MallocHook::Add##hook_type(                                   \
        (MallocHook::hook_type)&IncrementCallsTo##hook_type));          \
  }                                                                     \
  static void Reset##hook_type() {                                      \
    g_##hook_type##_calls = 0;                                          \
    CHECK(MallocHook::Remove##hook_type(                                \
        (MallocHook::hook_type)&IncrementCallsTo##hook_type));          \
  }

// We do one for each hook typedef in malloc_hook.h
MAKE_HOOK_CALLBACK(NewHook, const void*, size_t);
MAKE_HOOK_CALLBACK(DeleteHook, const void*);

static void TestAlignmentForSize(int size) {
  const size_t min_align = TestingPortal::Get()->GetMinAlign();

  printf("Testing alignment of malloc(%d)\n", size);
  static const int kNum = 100;
  void* ptrs[kNum];
  for (int i = 0; i < kNum; i++) {
    ptrs[i] = malloc(size);
    uintptr_t p = reinterpret_cast(ptrs[i]);
    CHECK((p % sizeof(void*)) == 0);
    CHECK((p % sizeof(double)) == 0);

    // Must have 16-byte (or 8-byte in case of -DTCMALLOC_ALIGN_8BYTES)
    // alignment for large enough objects
    if (size >= min_align) {
      CHECK((p % min_align) == 0);
    }
  }
  for (int i = 0; i < kNum; i++) {
    free(ptrs[i]);
  }
}

TEST(TCMallocTest, MallocAlignment) {
  for (int lg = 0; lg < 16; lg++) {
    TestAlignmentForSize((1<= min_size.
static void CheckRangeCallback(void* ptr, base::MallocRange::Type type,
                               size_t min_size) {
  bool matched = false;
  const uintptr_t addr = reinterpret_cast(ptr);
  auto callback = [&] (const base::MallocRange* r) -> void {
    if (!(r->address <= addr && addr < r->address + r->length)) {
      return;
    }

    if (type == base::MallocRange::FREE) {
      // We are expecting r->type == FREE, but ReleaseMemory
      // may have already moved us to UNMAPPED state instead (this happens in
      // approximately 0.1% of executions). Accept either state.
      CHECK(r->type == base::MallocRange::FREE ||
            r->type == base::MallocRange::UNMAPPED);
    } else {
      CHECK_EQ(r->type, type);
    }
    CHECK_GE(r->length, min_size);

    matched = true;
  };

  tcmalloc::FunctionRefFirstDataArg ref(callback);
  MallocExtension::instance()->Ranges(ref.data, ref.fn);
  EXPECT_TRUE(matched);
}

TEST(TCMallocTest, Ranges) {
  static const int MB = 1048576;
  void* a = malloc(MB);
  void* b = malloc(MB);
  base::MallocRange::Type releasedType =
    TestingPortal::Get()->HaveSystemRelease() ? base::MallocRange::UNMAPPED : base::MallocRange::FREE;

  CheckRangeCallback(a, base::MallocRange::INUSE, MB);
  CheckRangeCallback(b, base::MallocRange::INUSE, MB);

  (noopt(free))(a);

  CheckRangeCallback(a, base::MallocRange::FREE, MB);
  CheckRangeCallback(b, base::MallocRange::INUSE, MB);

  MallocExtension::instance()->ReleaseFreeMemory();

  CheckRangeCallback(a, releasedType, MB);
  CheckRangeCallback(b, base::MallocRange::INUSE, MB);

  (noopt(free))(b);

  CheckRangeCallback(a, releasedType, MB);
  CheckRangeCallback(b, base::MallocRange::FREE, MB);
}

static size_t GetUnmappedBytes() {
  size_t bytes;
  CHECK(MallocExtension::instance()->GetNumericProperty(
          "tcmalloc.pageheap_unmapped_bytes", &bytes));
  return bytes;
}

TEST(TCMallocTest, ReleaseToSystem) {
  // Debug allocation mode adds overhead to each allocation which
  // messes up all the equality tests here.  I just disable the
  // test in this mode.
  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    return;
  }

  if(!TestingPortal::Get()->HaveSystemRelease()) return;

  tcmalloc::Cleanup release_rate_cleanup = SetFlag(&TestingPortal::Get()->GetReleaseRate(), 0);
  tcmalloc::Cleanup decommit_cleanup = kAggressiveDecommit.Override(0);

  static const int MB = 1048576;
  void* a = noopt(malloc(MB));
  void* b = noopt(malloc(MB));
  MallocExtension::instance()->ReleaseFreeMemory();
  size_t starting_bytes = GetUnmappedBytes();

  // Calling ReleaseFreeMemory() a second time shouldn't do anything.
  MallocExtension::instance()->ReleaseFreeMemory();
  EXPECT_EQ(starting_bytes, GetUnmappedBytes());

  // ReleaseToSystem shouldn't do anything either.
  MallocExtension::instance()->ReleaseToSystem(MB);
  EXPECT_EQ(starting_bytes, GetUnmappedBytes());

  free(a);

  // The span to release should be 1MB.
  MallocExtension::instance()->ReleaseToSystem(MB/2);
  EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes());

  // Should do nothing since the previous call released too much.
  MallocExtension::instance()->ReleaseToSystem(MB/4);
  EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes());

  free(b);

  // Use up the extra MB/4 bytes from 'a' and also release 'b'.
  MallocExtension::instance()->ReleaseToSystem(MB/2);
  EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes());

  // Should do nothing since the previous call released too much.
  MallocExtension::instance()->ReleaseToSystem(MB/2);
  EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes());

  // Nothing else to release.
  MallocExtension::instance()->ReleaseFreeMemory();
  EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes());

  a = noopt(malloc(MB));
  free(a);
  EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes());

  // Releasing less than a page should still trigger a release.
  MallocExtension::instance()->ReleaseToSystem(1);
  EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes());
}

TEST(TCMallocTest, LargeAllocsRelease) {
  // Debug allocation mode adds overhead to each allocation which
  // messes up all the equality tests here.  I just disable the
  // test in this mode.
  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    return;
  }

  if(!TestingPortal::Get()->HaveSystemRelease()) return;

  tcmalloc::Cleanup release_rate_cleanup = SetFlag(&TestingPortal::Get()->GetReleaseRate(), 0);
  tcmalloc::Cleanup decommit_cleanup = kAggressiveDecommit.Override(0);

  // This test verifies special logic where page heap prefers reusing
  // normal spans over touching returned spans for large allocations
  // where spans are of the same size.
  //
  // We have the same logic for non-large spans.
  //
  // See github pull request
  // https://github.com/gperftools/gperftools/pull/1604 and commit
  // 32f11cb4b777880f7ecff3edcb5bc04fd6f1dff1 for motivation.

  constexpr size_t kNumPtrs = 10;
  constexpr size_t kBigAllocBytes = 3 << 20;

  std::vector> cleanup;
  std::vector> chunks;

  auto alloc_big = [&] () -> std::unique_ptr {
    return std::unique_ptr{noopt(new char[kBigAllocBytes])};
  };

  for (;;) {
    // Ensure there is big large chunk of memory that is available. We
    // want kNumPtrs * 2 successive chunks to be allocated in this
    // space. This test is explicitly very picky in what behavior it
    // triggers.
    free(noopt(malloc(kNumPtrs * 2 * kBigAllocBytes)));

    size_t i;
    for (i = 0; i < kNumPtrs * 2; i++) {
      chunks.emplace_back(alloc_big());
      if (i > 0) {
        if (chunks.rbegin()->get() != (chunks.rbegin()+1)->get() + kBigAllocBytes) {
          static int num_fail;
          printf("successive allocation failure %d. Will retry\n", ++num_fail);
          ASSERT_LE(num_fail, 32);
          break;
        }
      }
    }
    if (i == kNumPtrs * 2) {
      break; // success
    }

    // Whatever we've got so far, lets ensure it is cleaned up. But after the test.
    std::move(chunks.begin(), chunks.end(), std::back_inserter(cleanup));
    chunks.clear();
  }

  std::array, kNumPtrs> used_ptrs;
  std::array, kNumPtrs> free_ptrs;

  for (size_t i = 0; i < kNumPtrs; ++i) {
    // interleave used_ptrs and free_ptrs to prevent free_ptrs from coalescing
    used_ptrs[i] = std::move(chunks[i * 2]);
    free_ptrs[i] = std::move(chunks[i * 2 + 1]);
  }

  MallocExtension::instance()->ReleaseFreeMemory();

  size_t starting_bytes = GetUnmappedBytes();

  for (auto& ptr : free_ptrs) {
    ptr.reset();
  }
  // Ensure that free-s just above did not cause any returns of memory
  // to the kernel.
  EXPECT_EQ(starting_bytes, GetUnmappedBytes());

  // Here is the logic. So we're at the stage where only normal spans
  // are from free-s (unique_ptr resets) just above. And there is some
  // number of returned spans. As we call ReleaseToSystem with the
  // exact span size, we will return one of those to the kernel and
  // move the span to returned list.
  for (size_t i = 0; i < 2 * kNumPtrs; ++i) {
    MallocExtension::instance()->ReleaseToSystem(kBigAllocBytes);
    // Then we expect the following allocation to take one of those
    // normal spans (despite just returned span to have lower address).
    //
    // I.e. we want to avoid allocating the memory we just returned to
    // the kernel. Which would grow RSS unnecessarily.
    auto a = alloc_big();
    a.reset();
  }
  MallocExtension::instance()->ReleaseToSystem(kBigAllocBytes);
  // And finally we ensure that, indeed, we've returned all the chunks
  // we've freed.
  EXPECT_EQ(starting_bytes + kNumPtrs * kBigAllocBytes, GetUnmappedBytes());
}

TEST(TCMallocTest, AggressiveDecommit) {
  // Debug allocation mode adds overhead to each allocation which
  // messes up all the equality tests here.  I just disable the
  // teset in this mode.
  if(TestingPortal::Get()->IsDebuggingMalloc() || !TestingPortal::Get()->HaveSystemRelease()) {
    return;
  }

  printf("Testing aggressive de-commit\n");

  MallocExtension::instance()->ReleaseFreeMemory();

  tcmalloc::Cleanup cleanup = kAggressiveDecommit.Override(1);

  static const int MB = 1048576;
  void* a = noopt(malloc(MB));
  void* b = noopt(malloc(MB));

  size_t starting_bytes = GetUnmappedBytes();

  // ReleaseToSystem shouldn't do anything either.
  MallocExtension::instance()->ReleaseToSystem(MB);
  EXPECT_EQ(starting_bytes, GetUnmappedBytes());

  free(a);

  // The span to release should be 1MB.
  EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes());

  free(b);

  EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes());

  // Nothing else to release.
  MallocExtension::instance()->ReleaseFreeMemory();
  EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes());

  a = noopt(malloc(MB));
  free(a);

  EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes());

  printf("Done testing aggressive de-commit\n");
}

// On MSVC10, in release mode, the optimizer convinces itself
// g_no_memory is never changed (I guess it doesn't realize OnNoMemory
// might be called).  Work around this by setting the var volatile.
volatile bool g_no_memory;
std::new_handler g_old_handler;
static void OnNoMemory() {
  g_no_memory = true;
  std::set_new_handler(g_old_handler);
}

TEST(TCMallocTest, SetNewMode) {
  int old_mode = tc_set_new_mode(1);

  g_old_handler = std::set_new_handler(&OnNoMemory);
  g_no_memory = false;
  void* ret = noopt(malloc(noopt(kTooBig)));
  EXPECT_EQ(nullptr, ret);
  EXPECT_TRUE(g_no_memory);

  g_old_handler = std::set_new_handler(&OnNoMemory);
  g_no_memory = false;
  ret = noopt(calloc(1, noopt(kTooBig)));
  EXPECT_EQ(nullptr, ret);
  EXPECT_TRUE(g_no_memory);

  g_old_handler = std::set_new_handler(&OnNoMemory);
  g_no_memory = false;
  ret = noopt(realloc(nullptr, noopt(kTooBig)));
  EXPECT_EQ(nullptr, ret);
  EXPECT_TRUE(g_no_memory);

  if (kOSSupportsMemalign) {
    // Not really important, but must be small enough such that
    // kAlignment + kTooBig does not overflow.
    const int kAlignment = 1 << 5;

    g_old_handler = std::set_new_handler(&OnNoMemory);
    g_no_memory = false;
    ret = Memalign(kAlignment, kTooBig);
    EXPECT_EQ(nullptr, ret);
    EXPECT_TRUE(g_no_memory);

    g_old_handler = std::set_new_handler(&OnNoMemory);
    g_no_memory = false;
    EXPECT_EQ(ENOMEM,
              PosixMemalign(&ret, kAlignment, kTooBig));
    EXPECT_EQ(nullptr, ret);
    EXPECT_TRUE(g_no_memory);
  }

  tc_set_new_mode(old_mode);
}

TEST(TCMallocTest, TestErrno) {
  void* ret;
  if (kOSSupportsMemalign) {
    errno = 0;
    ret = Memalign(128, kTooBig);
    EXPECT_EQ(nullptr, ret);
    EXPECT_EQ(ENOMEM, errno);
  }

  errno = 0;
  ret = noopt(malloc(noopt(kTooBig)));
  EXPECT_EQ(nullptr, ret);
  EXPECT_EQ(ENOMEM, errno);

  errno = 0;
  ret = tc_malloc_skip_new_handler(kTooBig);
  EXPECT_EQ(nullptr, ret);
  EXPECT_EQ(ENOMEM, errno);
}

// Ensure that nallocx works before main.
struct GlobalNallocx {
  GlobalNallocx() {
    if (!TestingPortal::Get()->IsDebuggingMalloc()) {
      CHECK_GT(nallocx(99, 0), 99);
    }
  }
} global_nallocx;

#if defined(__GNUC__)

static void check_global_nallocx() __attribute__((constructor));
static void check_global_nallocx() {
  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    return;
  }

  CHECK_GT(nallocx(99, 0), 99);
}

#endif // __GNUC__

static size_t GrowNallocxTestSize(size_t sz) {
  if (sz < 1024) {
    return sz + 7;
  }

  size_t divided = sz >> 7;
  divided |= (divided >> 1);
  divided |= (divided >> 2);
  divided |= (divided >> 4);
  divided |= (divided >> 8);
  divided |= (divided >> 16);
  divided += 1;
  return sz + divided;
}

TEST(TCMallocTest, NAllocX) {
  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    return;
  }

  for (size_t size = 0; size <= (1 << 20); size = GrowNallocxTestSize(size)) {
    size_t rounded = nallocx(size, 0);
    ASSERT_GE(rounded, size);
    void* ptr = malloc(size);
    ASSERT_EQ(rounded, MallocExtension::instance()->GetAllocatedSize(ptr));
    free(ptr);
  }
}

TEST(TCMallocTest, NAllocXAlignment) {
  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    return;
  }

  for (size_t size = 0; size <= (1 << 20); size = GrowNallocxTestSize(size)) {
    for (size_t align_log = 0; align_log < 10; align_log++) {
      size_t rounded = nallocx(size, MALLOCX_LG_ALIGN(align_log));
      size_t align = size_t{1} << align_log;
      ASSERT_GE(rounded, size);
      ASSERT_EQ(rounded % align, 0);
      void* ptr = tc_memalign(align, size);
      ASSERT_EQ(rounded, MallocExtension::instance()->GetAllocatedSize(ptr));
      free(ptr);
    }
  }
}

struct NewHandlerHelper {
  NewHandlerHelper(NewHandlerHelper* prev) : prev(prev) {
    memset(filler, 0, sizeof(filler));
  }

  NewHandlerHelper* Pop() {
    NewHandlerHelper* prev = this->prev;
    delete this;
    return prev;
  }

  NewHandlerHelper* const prev;
  char filler[512];
};

static int saw_new_handler_runs;
static NewHandlerHelper* oom_test_last_ptr;

static void test_new_handler() {
  oom_test_last_ptr = oom_test_last_ptr->Pop();
  saw_new_handler_runs++;
}

TEST(TCMallocTest, NewHandler) {
  if (running_fork_testing) return;

  // debug allocator does internal allocations and crashes when such
  // internal allocation fails. So don't test it.
  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    return;
  }

  ASSERT_EQ(oom_test_last_ptr, nullptr);
  ASSERT_EQ(saw_new_handler_runs, 0);
  tcmalloc::Cleanup clean_oom_testers([] () {
    while (oom_test_last_ptr) {
      oom_test_last_ptr = oom_test_last_ptr->Pop();
    }
  });

  setup_oomable_sys_alloc();

  std::new_handler old = std::set_new_handler(test_new_handler);
  get_test_sys_alloc()->simulate_oom = true;
  tcmalloc::Cleanup restore_oom([] () {
    get_test_sys_alloc()->simulate_oom = false;
  });

  ASSERT_EQ(saw_new_handler_runs, 0);

  // After we enabled "simulate oom" behavior in sys allocator, we may
  // need to allocate a lot of NewHandlerHelper instances until all
  // the page heap free reserves are consumed and we're hitting
  // sysallocator. So we have a linked list of thoses and keep
  // allocating until we see our test_new_handler runs.
  //
  // Note, there is also slight chance that we'll hit crash while
  // failing to allocate internal metadata. It doesn't happen often
  // (and not with default order of tests), but something we'll need
  // to fix one day.
  for (int i = 1<<24; i > 0; i--) {
    oom_test_last_ptr = noopt(new NewHandlerHelper(oom_test_last_ptr));
    ASSERT_NE(oom_test_last_ptr, nullptr);
    if (saw_new_handler_runs) {
      break;
    }
  }

  ASSERT_EQ(saw_new_handler_runs, 1);

  std::set_new_handler(old);
}

TEST(TCMallocTest, AllTests) {
  AllocatorState rnd(100);

  // Check that empty allocation works
  printf("Testing empty allocation\n");
  {
    void* p1 = rnd.alloc(0);
    ASSERT_NE(p1, nullptr);
    void* p2 = rnd.alloc(0);
    ASSERT_NE(p2, nullptr);
    ASSERT_NE(p1, p2);
    free(p1);
    free(p2);
  }

  // This code stresses some of the memory allocation via STL.
  // It may call operator delete(void*, nothrow_t).
  printf("Testing STL use\n");
  {
    std::vector v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(0);
    std::stable_sort(v.begin(), v.end());
  }

#ifdef ENABLE_SIZED_DELETE
  {
    printf("Testing large sized delete is not crashing\n");
    // Large sized delete
    // case. https://github.com/gperftools/gperftools/issues/1254
    std::vector addresses;
    constexpr int kSizedDepth = 1024;
    addresses.reserve(kSizedDepth);
    for (int i = 0; i < kSizedDepth; i++) {
      addresses.push_back(noopt(new char[12686]));
    }
    for (int i = 0; i < kSizedDepth; i++) {
      ::operator delete[](addresses[i], 12686);
    }
  }
#endif

  // Test each of the memory-allocation functions once, just as a sanity-check
  printf("Sanity-testing all the memory allocation functions\n");
  {
    // We use new-hook and delete-hook to verify we actually called the
    // tcmalloc version of these routines, and not the libc version.
    SetNewHook();      // defined as part of MAKE_HOOK_CALLBACK, above
    SetDeleteHook();   // ditto
    tcmalloc::Cleanup unhook([] () {
      // Reset the hooks to what they used to be.  These are all
      // defined as part of MAKE_HOOK_CALLBACK, above.
      ResetNewHook();
      ResetDeleteHook();
    });

    void* p1 = noopt(malloc)(10);
    ASSERT_NE(p1, nullptr);    // force use of this variable
    VerifyNewHookWasCalled();
    // Also test the non-standard tc_malloc_size
    size_t actual_p1_size = tc_malloc_size(p1);
    ASSERT_GE(actual_p1_size, 10);
    ASSERT_LT(actual_p1_size, 100000);   // a reasonable upper-bound, I think
    free(p1);
    VerifyDeleteHookWasCalled();

    p1 = noopt(malloc)(10);
    ASSERT_NE(p1, nullptr);
    VerifyNewHookWasCalled();
    tc_free_sized(p1, 10);
    VerifyDeleteHookWasCalled();

    // sadly windows stuff lacks aligned_alloc
    // (https://learn.microsoft.com/en-us/cpp/standard-library/cstdlib?view=msvc-170#remarks-6)
    p1 = noopt(tc_memalign)(1, 10);
    ASSERT_NE(p1, nullptr);
    VerifyNewHookWasCalled();
    tc_free_aligned_sized(p1, 1, 10);
    VerifyDeleteHookWasCalled();

    p1 = tc_malloc_skip_new_handler(10);
    ASSERT_NE(p1, nullptr);
    VerifyNewHookWasCalled();
    free(p1);
    VerifyDeleteHookWasCalled();

    p1 = noopt(calloc)(10, 2);
    ASSERT_NE(p1, nullptr);
    VerifyNewHookWasCalled();
    // We make sure we realloc to a big size, since some systems (OS
    // X) will notice if the realloced size continues to fit into the
    // malloc-block and make this a noop if so.
    p1 = noopt(realloc)(p1, 30000);
    ASSERT_NE(p1, nullptr);
    VerifyNewHookWasCalled();
    VerifyDeleteHookWasCalled();
    free(p1);
    VerifyDeleteHookWasCalled();

    if (kOSSupportsMemalign) {
      ASSERT_EQ(noopt(PosixMemalign)(&p1, sizeof(p1), 40), 0);
      ASSERT_NE(p1, nullptr);
      VerifyNewHookWasCalled();
      free(p1);
      VerifyDeleteHookWasCalled();

      p1 = noopt(Memalign)(sizeof(p1) * 2, 50);
      ASSERT_NE(p1, nullptr);
      VerifyNewHookWasCalled();
      free(p1);
      VerifyDeleteHookWasCalled();
    }

    // Windows has _aligned_malloc.  Let's test that that's captured too.
#if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(PERFTOOLS_NO_ALIGNED_MALLOC)
    p1 = noopt(_aligned_malloc)(sizeof(p1) * 2, 64);
    ASSERT_NE(p1, nullptr);
    VerifyNewHookWasCalled();
    _aligned_free(p1);
    VerifyDeleteHookWasCalled();
#endif

    p1 = noopt(valloc(60));
    ASSERT_NE(p1, nullptr);
    VerifyNewHookWasCalled();
    free(p1);
    VerifyDeleteHookWasCalled();

    p1 = noopt(pvalloc(70));
    ASSERT_NE(p1, nullptr);
    VerifyNewHookWasCalled();
    free(p1);
    VerifyDeleteHookWasCalled();

    char* p2 = noopt(new char);
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    delete p2;
    VerifyDeleteHookWasCalled();

    p2 = noopt(new char[100]);
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    delete[] p2;
    VerifyDeleteHookWasCalled();

    p2 = noopt(new (std::nothrow) char);
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    delete p2;
    VerifyDeleteHookWasCalled();

    p2 = noopt(new (std::nothrow) char[100]);
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    delete[] p2;
    VerifyDeleteHookWasCalled();

    // Another way of calling operator new
    p2 = noopt(static_cast(::operator new(100)));
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    ::operator delete(p2);
    VerifyDeleteHookWasCalled();

    // Try to call nothrow's delete too.  Compilers use this.
    p2 = noopt(static_cast(::operator new(100, std::nothrow)));
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    ::operator delete(p2, std::nothrow);
    VerifyDeleteHookWasCalled();

#ifdef ENABLE_SIZED_DELETE
    p2 = noopt(new char);
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    ::operator delete(p2, sizeof(char));
    VerifyDeleteHookWasCalled();

    p2 = noopt(new char[100]);
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    ::operator delete[](p2, sizeof(char) * 100);
    VerifyDeleteHookWasCalled();
#endif

    overaligned_type* poveraligned = noopt(new overaligned_type);
    ASSERT_NE(poveraligned, nullptr);
    ASSERT_EQ((((size_t)poveraligned) % kOveralignment), 0);
    VerifyNewHookWasCalled();
    delete poveraligned;
    VerifyDeleteHookWasCalled();

    poveraligned = noopt(new overaligned_type[10]);
    ASSERT_NE(poveraligned, nullptr);
    ASSERT_EQ((((size_t)poveraligned) % kOveralignment), 0);
    VerifyNewHookWasCalled();
    delete[] poveraligned;
    VerifyDeleteHookWasCalled();

    poveraligned = noopt(new(std::nothrow) overaligned_type);
    ASSERT_NE(poveraligned, nullptr);
    ASSERT_EQ((((size_t)poveraligned) % kOveralignment), 0);
    VerifyNewHookWasCalled();
    delete poveraligned;
    VerifyDeleteHookWasCalled();

    poveraligned = noopt(new(std::nothrow) overaligned_type[10]);
    ASSERT_NE(poveraligned, nullptr);
    ASSERT_EQ((((size_t)poveraligned) % kOveralignment), 0);
    VerifyNewHookWasCalled();
    delete[] poveraligned;
    VerifyDeleteHookWasCalled();

    // Another way of calling operator new
    p2 = noopt(static_cast(::operator new(100, std::align_val_t(kOveralignment))));
    ASSERT_NE(p2, nullptr);
    ASSERT_EQ((((size_t)p2) % kOveralignment), 0);
    VerifyNewHookWasCalled();
    ::operator delete(p2, std::align_val_t(kOveralignment));
    VerifyDeleteHookWasCalled();

    p2 = noopt(static_cast(::operator new(100, std::align_val_t(kOveralignment), std::nothrow)));
    ASSERT_NE(p2, nullptr);
    ASSERT_EQ((((size_t)p2) % kOveralignment), 0);
    VerifyNewHookWasCalled();
    ::operator delete(p2, std::align_val_t(kOveralignment), std::nothrow);
    VerifyDeleteHookWasCalled();

    poveraligned = noopt(new overaligned_type);
    ASSERT_NE(poveraligned, nullptr);
    ASSERT_EQ((((size_t)poveraligned) % kOveralignment), 0);
    VerifyNewHookWasCalled();
    ::operator delete(poveraligned, sizeof(overaligned_type), std::align_val_t(kOveralignment));
    VerifyDeleteHookWasCalled();

    poveraligned = noopt(new overaligned_type[10]);
    ASSERT_NE(poveraligned, nullptr);
    ASSERT_EQ((((size_t)poveraligned) % kOveralignment), 0);
    VerifyNewHookWasCalled();
    ::operator delete[](poveraligned, sizeof(overaligned_type) * 10, std::align_val_t(kOveralignment));
    VerifyDeleteHookWasCalled();

// On AIX user defined malloc replacement of libc routines
// cannot be done at link time must be done a runtime via
// environment variable MALLOCTYPE
#if !defined(_AIX)
    // Try strdup(), which the system allocates but we must free.  If
    // all goes well, libc will use our malloc!
    p2 = noopt(strdup("in memory of James Golick"));
    ASSERT_NE(p2, nullptr);
    VerifyNewHookWasCalled();
    free(p2);
    VerifyDeleteHookWasCalled();
#endif
  }

  // Check that "lots" of memory can be allocated
  printf("Testing large allocation\n");
  {
    const int mb_to_allocate = 100;
    void* p = rnd.alloc(mb_to_allocate << 20);
    ASSERT_NE(p, nullptr);  // could not allocate
    free(p);
  }

  // Check calloc() with various arguments
  printf("Testing calloc\n");
  TestCalloc(0, 0, true);
  TestCalloc(0, 1, true);
  TestCalloc(1, 1, true);
  TestCalloc(1<<10, 0, true);
  TestCalloc(1<<20, 0, true);
  TestCalloc(0, 1<<10, true);
  TestCalloc(0, 1<<20, true);
  TestCalloc(1<<20, 2, true);
  TestCalloc(2, 1<<20, true);
  TestCalloc(1000, 1000, true);

  TestCalloc(kMaxSize, 2, false);
  TestCalloc(2, kMaxSize, false);
  TestCalloc(kMaxSize, kMaxSize, false);

  TestCalloc(kMaxSignedSize, 3, false);
  TestCalloc(3, kMaxSignedSize, false);
  TestCalloc(kMaxSignedSize, kMaxSignedSize, false);

  // Do the memory intensive tests after threads are done, since exhausting
  // the available address space can make pthread_create to fail.

  // Check that huge allocations fail with nullptr instead of crashing
  printf("Testing huge allocations\n");
  TestHugeAllocations(&rnd);

  // Check that large allocations fail with nullptr instead of crashing
  //
  // debug allocation takes forever for huge allocs
  if (!TestingPortal::Get()->IsDebuggingMalloc()) {
    constexpr NumericProperty kHeapLimitMB{"tcmalloc.heap_limit_mb"};
    printf("Testing out of memory\n");
    tcmalloc::Cleanup cleanup_limit = kHeapLimitMB.Override(1<<10); // 1 gig. Note, this is in megs.
    // Don't exercise more than 1 gig, no need to.
    for (int s = 0; ; s += (10<<20)) {
      void* large_object = rnd.alloc(s);
      if (large_object == nullptr) {
        break;
      }
      free(large_object);
    }
  }
}

TEST(TCMallocTest, EmergencyMalloc) {
  auto portal = TestingPortal::Get();
  if (!portal->HasEmergencyMalloc()) {
    printf("EmergencyMalloc test skipped\n");
    return;
  }

  SetNewHook();
  SetDeleteHook();
  tcmalloc::Cleanup unhook([] () {
    ResetNewHook();
    ResetDeleteHook();
  });

  void* p1 = noopt(tc_malloc)(32);
  void* p2 = nullptr;

  VerifyNewHookWasCalled();

  portal->WithEmergencyMallocEnabled([&] () {
    p2 = noopt(malloc)(32);
  });

  ASSERT_NE(p2, nullptr);

  // Emergency malloc doesn't call hook
  ASSERT_EQ(g_NewHook_calls, 0);

  // Emergency malloc pointers are recognized by MallocExtension::GetOwnership
  ASSERT_EQ(MallocExtension::instance()->GetOwnership(p1), MallocExtension::kOwned);
  ASSERT_EQ(MallocExtension::instance()->GetOwnership(p2), MallocExtension::kOwned);

  EXPECT_FALSE(portal->IsEmergencyPtr(p1));
  EXPECT_TRUE(portal->IsEmergencyPtr(p2));

  // Emergency malloc automagically does the right thing for free()
  // calls and doesn't invoke hooks.
  free(p2);
  ASSERT_EQ(g_DeleteHook_calls, 0);

  free(p1);
  VerifyDeleteHookWasCalled();
}

TEST(TCMallocTest, EmergencyMallocNoHook) {
  auto portal = TestingPortal::Get();
  if (!portal->HasEmergencyMalloc()) {
    printf("EmergencyMallocNoHook test skipped\n");
    return;
  }

  void* p1 = noopt(tc_malloc)(32);
  void* p2 = nullptr;
  void* p3 = nullptr;
  void* p4 = nullptr;

  portal->WithEmergencyMallocEnabled([&] () {
    p2 = noopt(malloc)(32);
    for (int i = 11; i < 999; i++) {
      tc_free(p3);
      p3 = tc_calloc(1, i);
    }
    p4 = tc_calloc(4096, 1024);
  });

  ASSERT_NE(p2, nullptr);
  ASSERT_NE(p3, nullptr);
  ASSERT_NE(p4, nullptr);

  // Emergency malloc pointers are recognized by MallocExtension::GetOwnership
  ASSERT_EQ(MallocExtension::instance()->GetOwnership(p1), MallocExtension::kOwned);
  ASSERT_EQ(MallocExtension::instance()->GetOwnership(p2), MallocExtension::kOwned);
  ASSERT_EQ(MallocExtension::instance()->GetOwnership(p3), MallocExtension::kOwned);
  ASSERT_EQ(MallocExtension::instance()->GetOwnership(p4), MallocExtension::kOwned);

  EXPECT_FALSE(portal->IsEmergencyPtr(p1));
  EXPECT_TRUE(portal->IsEmergencyPtr(p2));
  EXPECT_TRUE(portal->IsEmergencyPtr(p3));
  EXPECT_TRUE(portal->IsEmergencyPtr(p4));

  SetNewHook();
  SetDeleteHook();
  tcmalloc::Cleanup unhook([] () {
    ResetNewHook();
    ResetDeleteHook();
  });

  // Emergency malloc automagically does the right thing for free()
  // calls and doesn't invoke hooks.
  free(p4);
  free(p3);
  free(p2);
  ASSERT_EQ(g_DeleteHook_calls, 0);

  free(p1);
  VerifyDeleteHookWasCalled();
}

TEST(TCMallocTest, ReallocVsFreeSized) {
  constexpr size_t kLargerSize = 256;
  constexpr size_t kSmallerSize = 160;

  void* p = noopt(realloc)(nullptr, kLargerSize);
  ASSERT_NE(p, nullptr);
  p = noopt(realloc)(p, kSmallerSize);
  ASSERT_NE(p, nullptr);

  // what we want to test is this: tc_free_sized(p, 80);
  // But how do we detect it's failure. So lets check explicitly

  void* p2 = noopt(malloc)(kSmallerSize);
  uint32_t small_size_class = TestingPortal::Get()->GetSizeClass(p2);
  free(p2);

  uint32_t realloced_size_class = TestingPortal::Get()->GetSizeClass(p);

  ASSERT_EQ(realloced_size_class, small_size_class);

  free(p);
}

TEST(TCMallocTest, ReallocOnInvalidPointer) {
  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    return;
  }

  static uint64_t mock_object[2] = {0x3955fe9622eede93, 0x42};
  static bool invalid_free_called;
  static bool invalid_get_size_called;

  auto invalid_free = +[] (void* ptr) {
    EXPECT_EQ(ptr, mock_object);
    invalid_free_called = true;
  };

  auto invalid_get_size = +[] (const void* ptr) -> size_t {
    EXPECT_EQ(ptr, mock_object);
    invalid_get_size_called = true;
    return sizeof(mock_object[0]);
  };

  invalid_free_called = false;
  invalid_get_size_called = false;

  void* p = TestingPortal::Get()->RunReallocWithCallback(
      mock_object, 128, invalid_free, invalid_get_size);

  ASSERT_NE(p, nullptr);
  ASSERT_EQ(MallocExtension::instance()->GetAllocatedSize(p), 128);
  ASSERT_NE(p, mock_object);
  ASSERT_TRUE(invalid_free_called);
  ASSERT_TRUE(invalid_get_size_called);

  // Verify that the contents of the object are preserved
  ASSERT_EQ(memcmp(p, &mock_object[0], sizeof(mock_object[0])), 0);
  // And that the second word of mock_object is not touched when copying
  ASSERT_NE(memcmp(p, &mock_object[1], sizeof(mock_object[1])), 0);

  free(p);
}

TEST(TCMallocTest, Version) {
  // Test tc_version()
  int major;
  int minor;
  const char* patch;
  char mmp[64];
  const char* human_version = tc_version(&major, &minor, &patch);
  int used = snprintf(mmp, sizeof(mmp), "gperftools %d.%d%s", major, minor, patch);
  ASSERT_LT(used, sizeof(mmp));
  ASSERT_EQ(strcmp(TC_VERSION_STRING, human_version), 0);
}

struct EnvProperty {
  const char* const name;
  constexpr EnvProperty(const char* name) : name(name) {}

  std::string_view Get() const {
    const char* v = getenv(name);
    if (v == nullptr) {
      return {};
    }
    return {v};
  }

  using override_set = std::vector>;
  using env_override_fn = std::function;

  static std::vector DuplicateAndUpdateEnv(env_override_fn fn) {
    override_set overrides;
    fn(&overrides);
    return DoDuplicateAndUpdateEnv(std::move(overrides));
  }

  static std::vector DoDuplicateAndUpdateEnv(override_set overrides) {
    std::vector vec;

    for (const char* const *p = environ; *p; p++) {
      std::string_view k_and_v{*p};
      auto pos = k_and_v.find('=');
      CHECK(pos != std::string_view::npos);
      std::string_view k = k_and_v.substr(0, pos);
      int i = overrides.size() - 1;;
      for (; i >= 0; i--) {
        if (overrides[i].first == k) {
          break;
        }
      }
      if (i < 0) {
        vec.push_back(*p);
      }
    }

    for (const auto& [k, v] : overrides) {
      if (v.empty()) {
        continue;
      }

      size_t sz = k.size() + v.size() + 1 + 1;
      char* new_k_and_v = new char[sz];
      auto it = std::copy(k.begin(), k.end(), new_k_and_v);
      *it++ = '=';
      it = std::copy(v.begin(), v.end(), it);
      *it++ = '\0';
      CHECK_EQ(it, new_k_and_v + sz);

      vec.push_back(new_k_and_v);
    }

    vec.push_back(nullptr);

    return vec;
  }

  void Set(override_set* overrides, const char* new_value) const {
    overrides->emplace_back(std::string(name), std::string(new_value));
  }
  void SetAndPrint(override_set* overrides, const char* new_value) const {
    printf("Testing %s=%s\n", name, new_value);
    return Set(overrides, new_value);
  }
};

static const char* argv0; // set in HandleVariableRuns

#ifndef _WIN32
// Everything non-windows we assume sufficiently POSIX-ish
static void ReSpawnWithEnv(EnvProperty::env_override_fn env_override) {
  std::vector env = EnvProperty::DuplicateAndUpdateEnv(env_override);
  char * const child_argv[] = {const_cast(argv0), nullptr};
  pid_t pid;
  int rv = posix_spawn(&pid, argv0, nullptr, nullptr, child_argv, const_cast(env.data()));
  if (rv != 0) {
    errno = rv;
    perror("posix_spawn");
    abort();
  }

  // parent
  int status = -1;
  pid_t wait_rv;
  do {
    wait_rv = waitpid(pid, &status, 0);
  } while (wait_rv < 0 && errno == EINTR);

  if (wait_rv < 0) {
    perror("waitpid");
    abort();
  }

  CHECK_EQ(wait_rv, pid);
  int exit_status = WEXITSTATUS(status);
  if (!WIFEXITED(status) || exit_status != 0) {
    printf("sub-process run failed with status = %d.\n", status);
    if (WIFEXITED(status)) {
      exit(exit_status);
    }
    exit(1);
  }
}
#else
// Windows spawning codes
static void ReSpawnWithEnv(EnvProperty::env_override_fn env_override) {
  std::vector env = EnvProperty::DuplicateAndUpdateEnv(env_override);

  // For windows CreateProcessA environment needs to be converted to
  // environment block. Which is just a successive ASCIIZ strings
  // terminated by \0 (blank string). So we convert our vector
  // environment entries to this format.
  env.pop_back(); // last element is nullptr

  std::vector env_views;
  env_views.reserve(env.size());
  size_t total_size = 0;
  for (const char* s : env) {
    env_views.push_back(s);
    total_size += env_views.rbegin()->size() + 1;
  }
  total_size++; // account for final empty string

  std::unique_ptr env_block = std::make_unique(total_size);
  char* env_block_p = env_block.get();
  for (std::string_view s : env_views) {
    env_block_p = std::copy(s.begin(), s.end(), env_block_p);
    *env_block_p++ = '\0';
  }
  *env_block_p++ = '\0';
  CHECK_EQ(env_block_p, &(env_block[total_size]));

  fflush(stdout);
  fflush(stderr);

  STARTUPINFOA si;
  PROCESS_INFORMATION pi;

  memset(&si, 0, sizeof(si));
  si.cb = sizeof(si);
  memset(&pi, 0, sizeof(pi));

  if (!CreateProcessA(argv0,
                      nullptr, // command line. nullptr implies just argv0
                      nullptr, // process attributes
                      nullptr, // thread attributes
                      TRUE,    // InheritHandles
                      0,       // creation flags
                      env_block.get(),
                      nullptr, // current directory
                      &si,
                      &pi)) {
    printf("CreateProcessA failed with error code: %x\n", (unsigned)GetLastError());
    abort();
  }

  WaitForSingleObject(pi.hProcess, INFINITE);

  DWORD exit_code;
  GetExitCodeProcess(pi.hProcess, &exit_code);

  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);

  if (exit_code != 0) {
    printf("sub-process run failed with status = %d\n", (int)exit_code);
    exit((int)exit_code);
  }
}
#endif // _WIN32

// We want to run tests with several runtime configuration tweaks. For
// improved test coverage. Previously we had shell script driving
// this, now we handle this by exec-ing just at the end of all tests.
//
// Do note, though, that this logic is only activated if test program
// is run with no args. I.e. if you're debugging specific unit-test(s)
// by passing --gtest_filter or other flags, you'll need to set up
// environment variables yourself. See SetupExec below.
//
// We test 4 extra settings:
//
// * TCMALLOC_TRANSFER_NUM_OBJ = 40
//
// * TCMALLOC_TRANSFER_NUM_OBJ = 4096
//
// * TCMALLOC_AGGRESSIVE_DECOMMIT = t
//
// * TCMALLOC_HEAP_LIMIT_MB = 512
//
// * TCMALLOC_ENABLE_SIZED_DELETE = t (note, this one is no-op in most
//     common builds)
void HandleVariableRuns(int argc, char** argv) {
  if (argc != 1) {
    return;
  }

  argv0 = argv[0];

  static constexpr EnvProperty kMarker{"TCMALLOC_UNITTEST_MARKER"};
  static constexpr EnvProperty kTransferNumObjEnv{"TCMALLOC_TRANSFER_NUM_OBJ"};
  static constexpr EnvProperty kAggressiveDecommitEnv{"TCMALLOC_AGGRESSIVE_DECOMMIT"};
  static constexpr EnvProperty kHeapLimitEnv{"TCMALLOC_HEAP_LIMIT_MB"};
  static constexpr EnvProperty kEnableSizedDeleteEnv{"TCMALLOC_ENABLE_SIZED_DELETE"};

  if (!kMarker.Get().empty()) {
    return; // We're unitttest child
  }

  using override_set = EnvProperty::override_set;

  ReSpawnWithEnv([] (override_set* overrides) {
    kMarker.Set(overrides, "_");
  });

  ReSpawnWithEnv([] (override_set* overrides) {
    kTransferNumObjEnv.SetAndPrint(overrides, "40");
    kMarker.Set(overrides, "_");
  });

  ReSpawnWithEnv([] (override_set* overrides) {
    kTransferNumObjEnv.SetAndPrint(overrides, "4096");
    kMarker.Set(overrides, "_");
  });

  ReSpawnWithEnv([] (override_set* overrides) {
    kTransferNumObjEnv.Set(overrides, "");
    kAggressiveDecommitEnv.SetAndPrint(overrides, "t");
    kMarker.Set(overrides, "_");
  });

  ReSpawnWithEnv([] (override_set* overrides) {
    kAggressiveDecommitEnv.Set(overrides, "");
    kHeapLimitEnv.SetAndPrint(overrides, "512");
    kMarker.Set(overrides, "_");
  });

  ReSpawnWithEnv([] (override_set* overrides) {
    kHeapLimitEnv.Set(overrides, "");
    kEnableSizedDeleteEnv.SetAndPrint(overrides, "t");
    kMarker.Set(overrides, "_");
  });

  exit(0);
}

#ifdef HAVE_FORK_TESTING_SUPPORT
namespace fork_torture {

// Fork torture testing.
//
// Basic idea is to enable x86 single-stepping mode. And have signal
// handler for SIGTRAP wake up a helper thread. That helper thread
// forks and runs some malloc activities in the child.
//
// We also setup cpu mask with exactly one cpu and have helper thread
// on real-time scheduling policy. This ensures that whenever helper
// thread runs forking, we can unblock main thread, but main thread
// will only run when helper thread is blocked on some lock.
//
// Intended outcome is to exercise fork in multithreaded programs on
// roughly every possible opportunity.
//
// We also add a small optimization of only really stopping on
// instructions immediately after instruction with LOCK
// prefix. I.e. after some locking operation is complete.
//
// This is Linux- and x86-64-specific for simplicity.

// single_step_req is waited by the helper thread and posted by main
// thread from single-step signal handler.
sem_t single_step_req;
// single_step_ack is waited by the main thread and posted by the
// helper thread.
sem_t single_step_ack;

// in_fork is a flag set iff helper thread is running the forking activity.
bool in_fork;

// These 2 flags are helping us make sure we're actually done forking
// at the end of test runner.
bool stepping_stop_requested;
bool stepping_stop_acked;

uint64_t num_forks;

void xsem_wait(sem_t* sem) {
  while (sem_wait(sem) < 0) {
    CHECK(errno == EINTR);
  }
}

constexpr uintptr_t kTF = 0x100; // Trace flag in x86 FLAGS register.

bool try_handle_sigtrap_blocking(uint8_t* at_rip, ucontext_t* uc);

void step_handler(int signo, siginfo_t* si, void* _uc) {
  ucontext_t* uc = static_cast(_uc);
  auto at_rip = reinterpret_cast(uc->uc_mcontext.gregs[REG_RIP]);

  if (stepping_stop_requested) {
    uc->uc_mcontext.gregs[REG_EFL] &= ~kTF;
    while (in_fork) {
      (void)*const_cast(&in_fork);
    }
    stepping_stop_acked = true;
    return;
  }

  if (try_handle_sigtrap_blocking(at_rip, uc)) {
    return;
  }

  if (in_fork) {
    return;
  }

  // Add TF to flags and request SIGTRAP on every instruction in this
  // thread. We could do it only once, but it is harmless to do it
  // always.
  uc->uc_mcontext.gregs[REG_EFL] |= kTF;

  static bool last_was_lock;

  if (!last_was_lock) {
    if (*at_rip == 0xf0) { // lock prefix.
      last_was_lock = true;
    }
    return;
  }

  last_was_lock = false;

  int errno_save = errno;

  (void)sem_post(&single_step_req);
  xsem_wait(&single_step_ack);

  errno = errno_save;
}

bool try_handle_sigtrap_blocking(uint8_t* at_rip, ucontext_t* uc) {
  if (at_rip[0] != 0x0f || at_rip[1] != 0x05) {
    return false;
  }

  // syscall instruction. Lets check if someone is about to block
  // SIGTRAP. If so we must turn off single-stepping, because
  // otherwise blocked SIGTRAP and pending single-stepping will kill
  // the process.

  auto& regs = uc->uc_mcontext.gregs;
  if (regs[REG_RAX] != SYS_rt_sigprocmask) {
    return false;
  }
  if (regs[REG_RDI] != SIG_SETMASK && regs[REG_RDI] != SIG_BLOCK) {
    return false;
  }
  sigset_t* newmask = reinterpret_cast(regs[REG_RSI]);
  if (!newmask || !sigismember(newmask, SIGTRAP)) {
    return false;
  }

  // okay, once we detected this case, we drop single-stepping
  // flag, block SIGTRAP and raise it. So that when SIGTRAP is
  // eventually unblocked, we'll get back to signal hander and
  // re-set single-stepping back.
  regs[REG_EFL] &= ~kTF;
  raise(SIGTRAP);
  sigset_t* oldmask = reinterpret_cast(regs[REG_RDX]);
  if (oldmask) {
    *oldmask = uc->uc_sigmask;
    regs[REG_RDX] = 0; // handle "get old mask" part, so we can block
                       // our signal
  }
  sigaddset(&uc->uc_sigmask, SIGTRAP);

  return true;
}

tcmalloc::Cleanup> setup_fork_testing(int* argc, char *** argv) {
  if (*argc < 2 || (*argv)[1] != std::string("--with-fork-torture")) {
    printf("Not enabling fork torture\n");
    return tcmalloc::Cleanup(std::function([] () {}));
  }
  printf("Enabling fork torturing!!!!\n");

  CHECK(sem_init(&single_step_req, 0, 0) == 0);
  CHECK(sem_init(&single_step_ack, 0, 0) == 0);

  // First, we set cpu affinity mask to only core 0. It helps
  // performance, but mostly it is required so that main thread never
  // runs when real-time helper thread is runnable.
  {
    cpu_set_t mask;
    memset(&mask, 0, sizeof(mask));
    CPU_SET(0, &mask);
    CHECK(sched_setaffinity(0, sizeof(mask), &mask) == 0);
  }

  // Then we prepare SIGTRAP signal handler.
  {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction = step_handler;
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
    CHECK(sigaction(SIGTRAP, &sa, nullptr) == 0);
  }

  std::thread* t = new std::thread([] () {
    // Helper thread first makes itself real-time.
    struct sched_param p;
    memset(&p, 0, sizeof(p));
    p.sched_priority = 1;
    CHECK(sched_setscheduler(0, SCHED_FIFO, &p) == 0);

    // And then signals its readiness.
    sem_post(&single_step_ack);

    MallocExtension::instance()->MarkThreadIdle();

    constexpr int kPeriod = 1 << 10;
    int cnt = kPeriod;

    while (true) {
      xsem_wait(&single_step_req);
      // Lets print something every few iterations to help us see if
      // progress is being made.
      if (--cnt <= 0) {
        write(2, "$", 1);
        cnt = kPeriod;
      }

      // Once we're about to fork, we need to flag "in_fork" mode and
      // unblock main thread.
      in_fork = true;
      sem_post(&single_step_ack);

      int child = fork();
      CHECK(child >= 0);
      if (child == 0) {
        // Child runs some mallocs and exits.
        (::operator delete)((::operator new)(32));
        (::operator delete)((::operator new)(1024));
        (::operator delete)((::operator new)(2 << 20));
        _exit(0);
      }

      // Parent asserts that child exited cleanly.
      int status = 0;
      int ret = waitpid(child, &status, 0);
      CHECK(ret == child);
      CHECK(status == 0);

      // And we un-mark in_fork mode, so that main thread continues to
      // cooperation via sem_{post/wait} on single_step_{req,ack}
      // semaphores.
      num_forks++;
      in_fork = false;
    }
  });
  (void)t; // leak
  xsem_wait(&single_step_ack);

  MallocExtension::instance()->MarkThreadIdle();

  // First SIGTRAP runs the signal handler and signal handler sets up
  // EFLAGS to single-step.
  raise(SIGTRAP);

  // This is a flag for a test that is not compatible with
  // single-stepping. NewHandler test doesn't work because it enables
  // oom simulation at some point which, naturally, crashes the forked
  // child.
  running_fork_testing = true;

  return tcmalloc::Cleanup(std::function([] () {
    stepping_stop_requested = true;
    while (!*const_cast(&stepping_stop_acked)) {
      // no-op
    }
    // In the clean up, we're ensuring that in_fork turns to false, so
    // that fork/waitpid isn't stuck.
    printf("Done with fork torturing! Number of forks performed: %lld\n", (long long)num_forks);
  }));
}
}  // namespace fork_torture

using fork_torture::setup_fork_testing;

#else  // HAVE_FORK_TESTING_SUPPORT

int setup_fork_testing(int* argc, char *** argv) {return 0;}

#endif  // !HAVE_FORK_TESTING_SUPPORT

int main(int argc, char** argv) {
  HandleVariableRuns(argc, argv);

  if (TestingPortal::Get()->IsDebuggingMalloc()) {
    // return freed blocks to tcmalloc immediately
    TestingPortal::Get()->GetMaxFreeQueueSize() = 0;
  }

#if defined(__linux) || defined(_WIN32)
  // We know that Linux and Windows have functional memory releasing
  // support. So don't let us degrade on that.
  if (!getenv("DONT_TEST_SYSTEM_RELEASE")) {
    CHECK(TestingPortal::Get()->HaveSystemRelease());
  }
#endif

  testing::InitGoogleTest(&argc, argv);

  auto fork_cleanup = setup_fork_testing(&argc, &argv);
  (void)fork_cleanup;

  int err_code = RUN_ALL_TESTS();
  if (err_code) {
    return err_code;
  }
}
gperftools-gperftools-2.18/src/tests/testutil.cc000066400000000000000000000046001513545575200221430ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein
//
// A few routines that are useful for multiple tests in this directory.

#include "config_for_unittests.h"

#include "tests/testutil.h"

#include 

#include 
#include 
#include 

extern "C" {
  void RunThread(void (*fn)()) {
    std::thread{fn}.join();
  }

  static void RunMany(const std::function& fn, int count) {
    std::vector threads;
    threads.reserve(count);
    for (int i = 0; i < count; i++) {
      threads.emplace_back(fn, i);
    }
    for (auto& t : threads) {
      t.join();
    }
  }

  void RunManyThreads(void (*fn)(), int count) {
    RunMany([fn] (int dummy) {
      fn();
    }, count);
  }

  void RunManyThreadsWithId(void (*fn)(int), int count) {
    RunMany(fn, count);
  }
}
gperftools-gperftools-2.18/src/tests/testutil.h000066400000000000000000000053771513545575200220210ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Craig Silverstein

#ifndef TCMALLOC_TOOLS_TESTUTIL_H_
#define TCMALLOC_TOOLS_TESTUTIL_H_

// Run a function in a thread of its own and wait for it to finish.
// The function you pass in must have the signature
//    void MyFunction();
extern "C" void RunThread(void (*fn)());

// Run a function X times, in X threads, and wait for them all to finish.
// The function you pass in must have the signature
//    void MyFunction();
extern "C" void RunManyThreads(void (*fn)(), int count);

// The 'advanced' version: run a function X times, in X threads, and
// wait for them all to finish.
// The function you pass in must have the signature
//    void MyFunction(int idx);
// where idx is the index of the thread (which of the X threads this is).
extern "C" void RunManyThreadsWithId(void (*fn)(int), int count);

static void (* volatile noopt_helper)(void *) = [] (void* dummy) {};

// This function forces compiler to forget specific knowledge about
// value of 'val'. This is useful to avoid compiler optimizing out
// new/delete pairs for our unit tests.
template 
T noopt(T val) {
  noopt_helper(&val);
  return val;
}

#endif  // TCMALLOC_TOOLS_TESTUTIL_H_
gperftools-gperftools-2.18/src/tests/thread_dealloc_unittest.cc000066400000000000000000000142431513545575200251630ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2004, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat
//
// Check that we do not leak memory when cycling through lots of threads.

#include "config_for_unittests.h"
#include 

#include 
#include 
#include 

#include "base/logging.h"

// Size/number of objects to allocate per thread (1 MB per thread)
static const int kObjectSize = 1024;
static const int kNumObjects = 1024;

size_t GetThreadHeapCount() {
  size_t rv;
  CHECK(MallocExtension::instance()->GetNumericProperty("tcmalloc.impl.thread_cache_count", &rv));
  return rv;
}

// This breaks on glibc. What happens is do_early_stuff below is run
// early on AllocStuff thread. It calls to pthread_setspecific which
// (being first setspecific for range of keys [32,64) ), will
// calloc. That calloc call will create thread cache and
// pthread_setspecific to 'nearby' pthread_key. Then calloc returns
// and original call to setspecific overwrites array of TLS
// values. And "looses" pthread_setspecific update we made as part of
// initializing thread cache.
//
// Do note, though, that attribute constructor trick only succeeds to
// reproduce the issue when tcmalloc is linked statically to this
// test. Only then we're able to "insert" a bunch of pthread keys
// before tcmalloc allocates its own.
//
// Why glibc works in regular case? Because usually pthread_key_t
// value for ThreadCache instance is allocated early. So it gets low
// numeric key value. And for those low numeric values, glibc uses
// "static" TLS storage, which is safe. It looks like glibc does that
// specifically to enable our (and other malloc implementations) case.
//
// Similar cases might happen on other pthread implementations
// (depending on how, if at all, their pthread_setspecific
// implementation does malloc). There appears to be no portable way to
// prevent this problem.
//
// Mingw's libwinpthread would simply deadlock. They do call into
// malloc, and they don't allow *any* reentrancy into pthread TLS
// bits. But we're using windows native TLS there.
//
// Musl and bionic use "static" arrays for thread specific values, so
// we're safe there. Same applies to NetBSD.
//
// FreeBSD appears to be using some internal memory allocation routine
// for allocation of storage thread specific values. So should be fine
// too. Same appears to be the case for OpenSolaris (and perhaps just
// Solaris), but they also no-memory-allocation thread specific for
// low pthread_key values (same as glibc).
//
// NOTE: jemalloc uses FreeBSD-specific _malloc_thread_cleanup, which
// explicitly avoids the issue. So we can do same if necessary.
#if defined(TEST_HARD_THREAD_DEALLOC)
static pthread_key_t early_tls_key;

static __attribute__((constructor(101)))
void early_stuff() {
  // When this is defined, the "leak" part is skipped. So both thread
  // cache and early_tls_key get low values, so we're passing the
  // test. See above for details.
  //
  // I.e. CPPFLAGS=-DTEST_HARD_THREAD_DEALLOC fails on glibc, and
  // 'CPPFLAGS=-DTEST_HARD_THREAD_DEALLOC -DTEST_LESS_HARD_THREAD_DEALLOC' works
#if !defined(TEST_LESS_HARD_THREAD_DEALLOC)
  pthread_key_t leaked;
  for (int i = 0; i < 32; i++) {
    CHECK(pthread_key_create(&leaked, nullptr) == 0);
  }
#endif

  CHECK(pthread_key_create(&early_tls_key, +[] (void* arg) {
    auto sz = reinterpret_cast(arg);
    (operator delete)((operator new)(sz));
  }) == 0);
}

static void do_early_stuff() {
  pthread_setspecific(early_tls_key, reinterpret_cast(uintptr_t{32}));
}
#else
static void do_early_stuff() {}
#endif

// Allocate lots of stuff
static void AllocStuff() {
  do_early_stuff();

  std::unique_ptr objects{new void*[kNumObjects]};

  for (int i = 0; i < kNumObjects; i++) {
    objects[i] = malloc(kObjectSize);
  }
  for (int i = 0; i < kNumObjects; i++) {
    free(objects[i]);
  }
}

int main(int argc, char** argv) {
  constexpr int kDisplaySize = 1 << 20;
  std::unique_ptr display{new char[kDisplaySize]};

  printf("thread count before: %zu\n", GetThreadHeapCount());

  // Number of threads to create and destroy
  constexpr int kNumThreads = 1000;

  for (int i = 0; i < kNumThreads; i++) {
    std::thread{AllocStuff}.join();

    if (((i+1) % 200) == 0) {
      printf("Iteration: %d of %d\n", (i+1), kNumThreads);
      MallocExtension::instance()->GetStats(display.get(), kDisplaySize);
      printf("%s\n", display.get());
      printf("Thread count: %zu\n", GetThreadHeapCount());
    }
  }

  size_t thread_count_after = GetThreadHeapCount();
  printf("thread count after: %zu\n", thread_count_after);
  CHECK_EQ(thread_count_after, 1);

  printf("PASS\n");

  return 0;
}
gperftools-gperftools-2.18/src/tests/unique_path_unittest.cc000066400000000000000000000160701513545575200245530ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2023, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// ---
// Author: Artem Y. Polyakov
// heavily massaged by alkondratenko@gmail.com, all bugs are mine

#include "config.h"

#include "base/sysinfo.h"

#include    // for PATH_MAX
#include    // for environment primitives
#include    // for getpid()

#include 
#include 

#include "gtest/gtest.h"

#include "base/commandlineflags.h"
#include "base/environ.h"
#include "base/logging.h"
#include "base/logging.h"
#include "base/commandlineflags.h"

struct WithEnv {
  char** const orig_environ = environ;

  struct EnvUpdate {
    std::vector new_environ;
    std::string var_val;
    EnvUpdate(const std::string& var, const std::string& val) {
      var_val = var;
      var_val.append(1, '=');
      var_val.append(val);
      new_environ.push_back(var_val.c_str());

      for (char** p = environ; *p != nullptr; p++) {
        new_environ.push_back(*p);
      }
      new_environ.push_back(nullptr);
    }
  };

  const EnvUpdate env_update;

  WithEnv(const std::string& var, const std::string& val) : env_update(var, val) {
    Reset();
  }
  ~WithEnv() {
    environ = orig_environ;
  }

  // GetUniquePathFromEnv updates environment variables, so this
  // re-sets environment to the values set by this WithEnv block.
  void Reset() {
    environ = const_cast(&(env_update.new_environ[0]));
  }
};

std::string AppendPID(const std::string &str) {
  return str + "_" + std::to_string(getpid());
}

#define TEST_VAR "GPROF_TEST_PATH"
#define TEST_VAL "/var/log/some_file_name"

std::string GetTestPath() {
  char path[PATH_MAX];
  CHECK(GetUniquePathFromEnv(TEST_VAR, path));
  return path;
}

TEST(GetUniquePathTest, Default) {
  WithEnv withTestVar(TEST_VAR, TEST_VAL);

  EXPECT_EQ(TEST_VAL, GetTestPath());

  // Now that we ran GetUniquePathFromEnv once, we can test "child"
  // case, which appends pid
  EXPECT_EQ(AppendPID(TEST_VAL), GetTestPath());

  withTestVar.Reset();
  WithEnv withForced(TEST_VAR "_USE_PID", "1");

  // Test parent case - must include PID (will set the child flag)
  EXPECT_EQ(AppendPID(TEST_VAL), GetTestPath());

  // Test child case
  EXPECT_EQ(AppendPID(TEST_VAL), GetTestPath());
}

// PMIx is one type of MPI environments that we detect specially. We
// expect .rank-${PMIX_RANK} to be appended when we detect this
// environment.
TEST(GetUniquePathTest, PMIx) {
  WithEnv rank("PMIX_RANK", "5");
  WithEnv withTestVar(TEST_VAR, TEST_VAL);

  const auto expectedParent = TEST_VAL ".rank-5";
  const auto expectedChild = AppendPID(expectedParent);

  // Test parent case (will set the child flag)
  EXPECT_EQ(expectedParent, GetTestPath());

  // Test child case
  EXPECT_EQ(expectedChild, GetTestPath());

  withTestVar.Reset();
  WithEnv withForced(TEST_VAR "_USE_PID", "1");

  // Test parent case (will set the child flag)
  EXPECT_EQ(expectedChild, GetTestPath());

  // Test child case
  EXPECT_EQ(expectedChild, GetTestPath());
}

// Slurm is another type of MPI environments that we detect
// specially. When only SLURM_JOB_ID is detected we force-append pid,
// when SLURM_PROCID is given, we append ".slurmid-${SLURM_PROCID}
TEST(GetUniquePathTest, Slurm) {
  WithEnv withJobID("SLURM_JOB_ID", "1");
  WithEnv withTestVar(TEST_VAR, TEST_VAL);

  auto pathWithPID = AppendPID(TEST_VAL);

  // Test non-forced case (no process ID found)
  EXPECT_EQ(pathWithPID, GetTestPath());

  // Now that we ran GetUniquePathFromEnv once, we can test "child"
  // case, which appends pid
  EXPECT_EQ(pathWithPID, GetTestPath());

  withTestVar.Reset();
  WithEnv withRank("SLURM_PROCID", "5");

  const auto expectedSlurmParent = TEST_VAL ".slurmid-5";
  const auto expectedSlurmChild = AppendPID(expectedSlurmParent);

  // Test parent case - must include "proc id" (will set the child flag)
  EXPECT_EQ(expectedSlurmParent, GetTestPath());

  // Test child case
  EXPECT_EQ(expectedSlurmChild, GetTestPath());

  withRank.Reset();
  WithEnv withForced(TEST_VAR "_USE_PID", "1");

  // Now that pid is forced we expect both pid and proc-id appended.
  EXPECT_EQ(expectedSlurmChild, GetTestPath());

  // Test child case
  EXPECT_EQ(expectedSlurmChild, GetTestPath());
}

// Open MPI is another type of MPI environments that we detect. We
// force-append pid if we detect it.
TEST(GetUniquePathTest, OMPI) {
  WithEnv withOMPI("OMPI_HOME", "/some/path");
  WithEnv withTestVar(TEST_VAR, TEST_VAL);

  const auto expectedPath = AppendPID(TEST_VAL);

  // Test parent case (will set the child flag)
  EXPECT_EQ(expectedPath, GetTestPath());

  // Test child case
  EXPECT_EQ(expectedPath, GetTestPath());

  withTestVar.Reset();
  WithEnv withForced(TEST_VAR "_USE_PID", "1");

  // Test parent case (will set the child flag)
  EXPECT_EQ(expectedPath, GetTestPath());

  // Test child case
  EXPECT_EQ(expectedPath, GetTestPath());
}

// MPICH is another type of MPI environment that we detect. We
// expect .rank-${PMI_RANK} to be appended when we detect this
// environment.
TEST(GetUniquePathTest, MPICH) {
  WithEnv rank("PMI_RANK", "5");
  WithEnv withTestVar(TEST_VAR, TEST_VAL);

  const auto expectedParent = TEST_VAL ".rank-5";
  const auto expectedChild = AppendPID(expectedParent);

  // Test parent case (will set the child flag)
  EXPECT_EQ(expectedParent, GetTestPath());

  // Test child case
  EXPECT_EQ(expectedChild, GetTestPath());

  withTestVar.Reset();
  WithEnv withForced(TEST_VAR "_USE_PID", "1");

  // Test parent case (will set the child flag)
  EXPECT_EQ(expectedChild, GetTestPath());

  // Test child case
  EXPECT_EQ(expectedChild, GetTestPath());
}
gperftools-gperftools-2.18/src/thread_cache.cc000066400000000000000000000337071513545575200215300ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Ken Ashcraft 

#include 

#include "thread_cache.h"

#include                     // for max, min

#include                      // for memcpy

#include "base/spinlock.h"              // for SpinLockHolder
#include "central_freelist.h"
#include "getenv_safe.h"                // for TCMallocGetenvSafe
#include "tcmalloc_internal.h"

// Note: this is initialized manually in InitModule to ensure that
// it's configured at right time
//
// DEFINE_int64(tcmalloc_max_total_thread_cache_bytes,
//              EnvToInt64("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES",
//                         kDefaultOverallThreadCacheSize),
//              "Bound on the total amount of bytes allocated to "
//              "thread caches. This bound is not strict, so it is possible "
//              "for the cache to go over this bound in certain circumstances. "
//              "Maximum value of this flag is capped to 1 GB.");


namespace tcmalloc {

static bool phinited = false;

volatile size_t ThreadCache::per_thread_cache_size_ = kMaxThreadCacheSize;

std::atomic ThreadCache::min_per_thread_cache_size_ = kMinThreadCacheSize;
size_t ThreadCache::overall_thread_cache_size_ = kDefaultOverallThreadCacheSize;
ssize_t ThreadCache::unclaimed_cache_space_ = kDefaultOverallThreadCacheSize;
PageHeapAllocator threadcache_allocator;
ThreadCache* ThreadCache::thread_heaps_;
int ThreadCache::thread_heap_count_;
ThreadCache* ThreadCache::next_memory_steal_;

ThreadCache::ThreadCache() {
  ASSERT(Static::pageheap_lock()->IsHeld());

  size_ = 0;

  max_size_ = 0;
  IncreaseCacheLimitLocked();
  if (max_size_ == 0) {
    // There isn't enough memory to go around.  Just give the minimum to
    // this thread.
    size_t min_size = min_per_thread_cache_size_.load(std::memory_order_relaxed);
    SetMaxSize(min_size);

    // Take unclaimed_cache_space_ negative.
    unclaimed_cache_space_ -= min_size;
    ASSERT(unclaimed_cache_space_ < 0);
  }

  next_ = nullptr;
  prev_ = nullptr;
  for (uint32_t cl = 0; cl < Static::num_size_classes(); ++cl) {
    list_[cl].Init(Static::sizemap()->class_to_size(cl));
  }

  uintptr_t sampler_seed;
  uintptr_t addr = reinterpret_cast(&sampler_seed);
  sampler_seed = addr;

  sampler_.Init(uint64_t{sampler_seed});
}

ThreadCache::~ThreadCache() {
  // Put unused memory back into central cache
  for (uint32_t cl = 0; cl < Static::num_size_classes(); ++cl) {
    if (list_[cl].length() > 0) {
      ReleaseToCentralCache(&list_[cl], cl, list_[cl].length());
    }
  }
}

// Remove some objects of class "cl" from central cache and add to thread heap.
// On success, return the first object for immediate use; otherwise return nullptr.
void* ThreadCache::FetchFromCentralCache(uint32_t cl, int32_t byte_size,
                                         void *(*oom_handler)(size_t size)) {
  FreeList* list = &list_[cl];
  ASSERT(list->empty());
  const int batch_size = Static::sizemap()->num_objects_to_move(cl);

  const int num_to_move = std::min(list->max_length(), batch_size);
  void *start, *end;
  int fetch_count = Static::central_cache()[cl].RemoveRange(
      &start, &end, num_to_move);

  if (fetch_count == 0) {
    ASSERT(start == nullptr);
    return oom_handler(byte_size);
  }
  ASSERT(start != nullptr);

  if (--fetch_count >= 0) {
    size_ += byte_size * fetch_count;
    list->PushRange(fetch_count, SLL_Next(start), end);
  }

  // Increase max length slowly up to batch_size.  After that,
  // increase by batch_size in one shot so that the length is a
  // multiple of batch_size.
  if (list->max_length() < batch_size) {
    list->set_max_length(list->max_length() + 1);
  } else {
    // Don't let the list get too long.  In 32 bit builds, the length
    // is represented by a 16 bit int, so we need to watch out for
    // integer overflow.
    int new_length = std::min(list->max_length() + batch_size,
                              kMaxDynamicFreeListLength);
    // The list's max_length must always be a multiple of batch_size,
    // and kMaxDynamicFreeListLength is not necessarily a multiple
    // of batch_size.
    new_length -= new_length % batch_size;
    ASSERT(new_length % batch_size == 0);
    list->set_max_length(new_length);
  }
  return start;
}

void ThreadCache::ListTooLong(FreeList* list, uint32_t cl) {
  size_ += list->object_size();

  const int batch_size = Static::sizemap()->num_objects_to_move(cl);
  ReleaseToCentralCache(list, cl, batch_size);

  // If the list is too long, we need to transfer some number of
  // objects to the central cache.  Ideally, we would transfer
  // num_objects_to_move, so the code below tries to make max_length
  // converge on num_objects_to_move.

  if (list->max_length() < batch_size) {
    // Slow start the max_length so we don't overreserve.
    list->set_max_length(list->max_length() + 1);
  } else if (list->max_length() > batch_size) {
    // If we consistently go over max_length, shrink max_length.  If we don't
    // shrink it, some amount of memory will always stay in this freelist.
    list->set_length_overages(list->length_overages() + 1);
    if (list->length_overages() > kMaxOverages) {
      ASSERT(list->max_length() > batch_size);
      list->set_max_length(list->max_length() - batch_size);
      list->set_length_overages(0);
    }
  }

  if (PREDICT_FALSE(size_ > max_size_)) {
    Scavenge();
  }
}

// Remove some objects of class "cl" from thread heap and add to central cache
void ThreadCache::ReleaseToCentralCache(FreeList* src, uint32_t cl, int N) {
  ASSERT(src == &list_[cl]);
  if (N > src->length()) N = src->length();
  size_t delta_bytes = N * Static::sizemap()->ByteSizeForClass(cl);

  // We return prepackaged chains of the correct size to the central cache.
  // TODO: Use the same format internally in the thread caches?
  int batch_size = Static::sizemap()->num_objects_to_move(cl);
  while (N > batch_size) {
    void *tail, *head;
    src->PopRange(batch_size, &head, &tail);
    Static::central_cache()[cl].InsertRange(head, tail, batch_size);
    N -= batch_size;
  }
  void *tail, *head;
  src->PopRange(N, &head, &tail);
  Static::central_cache()[cl].InsertRange(head, tail, N);
  size_ -= delta_bytes;
}

// Release idle memory to the central cache
void ThreadCache::Scavenge() {
  // If the low-water mark for the free list is L, it means we would
  // not have had to allocate anything from the central cache even if
  // we had reduced the free list size by L.  We aim to get closer to
  // that situation by dropping L/2 nodes from the free list.  This
  // may not release much memory, but if so we will call scavenge again
  // pretty soon and the low-water marks will be high on that call.
  for (int cl = 0; cl < Static::num_size_classes(); cl++) {
    FreeList* list = &list_[cl];
    const int lowmark = list->lowwatermark();
    if (lowmark > 0) {
      const int drop = (lowmark > 1) ? lowmark/2 : 1;
      ReleaseToCentralCache(list, cl, drop);

      // Shrink the max length if it isn't used.  Only shrink down to
      // batch_size -- if the thread was active enough to get the max_length
      // above batch_size, it will likely be that active again.  If
      // max_length shinks below batch_size, the thread will have to
      // go through the slow-start behavior again.  The slow-start is useful
      // mainly for threads that stay relatively idle for their entire
      // lifetime.
      const int batch_size = Static::sizemap()->num_objects_to_move(cl);
      if (list->max_length() > batch_size) {
        list->set_max_length(
          std::max(list->max_length() - batch_size, batch_size));
      }
    }
    list->clear_lowwatermark();
  }

  IncreaseCacheLimit();
}

void ThreadCache::IncreaseCacheLimit() {
  SpinLockHolder h(Static::pageheap_lock());
  IncreaseCacheLimitLocked();
}

void ThreadCache::IncreaseCacheLimitLocked() {
  if (unclaimed_cache_space_ > 0) {
    // Possibly make unclaimed_cache_space_ negative.
    unclaimed_cache_space_ -= kStealAmount;
    SetMaxSize(max_size_ + kStealAmount);
    return;
  }
  // Don't hold pageheap_lock too long.  Try to steal from 10 other
  // threads before giving up.  The i < 10 condition also prevents an
  // infinite loop in case none of the existing thread heaps are
  // suitable places to steal from.
  for (int i = 0; i < 10;
       ++i, next_memory_steal_ = next_memory_steal_->next_) {
    // Reached the end of the linked list.  Start at the beginning.
    if (next_memory_steal_ == nullptr) {
      ASSERT(thread_heaps_ != nullptr);
      next_memory_steal_ = thread_heaps_;
    }
    if (next_memory_steal_ == this ||
        next_memory_steal_->max_size_
          <= min_per_thread_cache_size_.load(std::memory_order_relaxed)) {
      continue;
    }
    next_memory_steal_->SetMaxSize(next_memory_steal_->max_size_ - kStealAmount);
    SetMaxSize(max_size_ + kStealAmount);

    next_memory_steal_ = next_memory_steal_->next_;
    return;
  }
}

int ThreadCache::GetSamplePeriod() {
  return Sampler::GetSamplePeriod();
}

void ThreadCache::InitModule() {
  {
    SpinLockHolder h(Static::pageheap_lock());
    if (phinited) {
      return;
    }
    const char *tcb = TCMallocGetenvSafe("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES");
    if (tcb) {
      set_overall_thread_cache_size(strtoll(tcb, nullptr, 10));
    }
    Static::InitStaticVars();
    threadcache_allocator.Init();
    SetupMallocExtension();
    phinited = 1;
  }

  // We do "late" part of initialization without holding lock since
  // there is chance it'll recurse into malloc
  Static::InitLateMaybeRecursive();

#ifndef NDEBUG
  // pthread_atfork above may malloc sometimes. Lets ensure we test
  // that malloc works from here.
  (operator delete)((operator new)(1));
#endif
}

ThreadCache* ThreadCache::NewHeap() {
  SpinLockHolder h(Static::pageheap_lock());

  // Create the heap and add it to the linked list
  ThreadCache *heap = new (threadcache_allocator.New()) ThreadCache();

  heap->next_ = thread_heaps_;
  heap->prev_ = nullptr;
  if (thread_heaps_ != nullptr) {
    thread_heaps_->prev_ = heap;
  } else {
    // This is the only thread heap at the momment.
    ASSERT(next_memory_steal_ == nullptr);
    next_memory_steal_ = heap;
  }
  thread_heaps_ = heap;
  thread_heap_count_++;
  return heap;
}

void ThreadCache::DeleteCache(ThreadCache* heap) {
  // Remove all memory from heap
  heap->~ThreadCache();

  // Remove from linked list
  SpinLockHolder h(Static::pageheap_lock());
  if (heap->next_ != nullptr) heap->next_->prev_ = heap->prev_;
  if (heap->prev_ != nullptr) heap->prev_->next_ = heap->next_;
  if (thread_heaps_ == heap) thread_heaps_ = heap->next_;
  thread_heap_count_--;

  if (next_memory_steal_ == heap) next_memory_steal_ = heap->next_;
  if (next_memory_steal_ == nullptr) next_memory_steal_ = thread_heaps_;
  unclaimed_cache_space_ += heap->max_size_;

  threadcache_allocator.Delete(heap);
}

void ThreadCache::RecomputePerThreadCacheSize() {
  // Divide available space across threads
  int n = thread_heap_count_ > 0 ? thread_heap_count_ : 1;
  size_t space = overall_thread_cache_size_ / n;

  size_t min_size = min_per_thread_cache_size_.load(std::memory_order_relaxed);
  // Limit to allowed range
  if (space < min_size) space = min_size;
  if (space > kMaxThreadCacheSize) space = kMaxThreadCacheSize;

  double ratio = space / std::max(1, per_thread_cache_size_);
  size_t claimed = 0;
  for (ThreadCache* h = thread_heaps_; h != nullptr; h = h->next_) {
    // Increasing the total cache size should not circumvent the
    // slow-start growth of max_size_.
    if (ratio < 1.0) {
      h->SetMaxSize(h->max_size_ * ratio);
    }
    claimed += h->max_size_;
  }
  unclaimed_cache_space_ = overall_thread_cache_size_ - claimed;
  per_thread_cache_size_ = space;
}

void ThreadCache::GetThreadStats(uint64_t* total_bytes, uint64_t* class_count) {
  for (ThreadCache* h = thread_heaps_; h != nullptr; h = h->next_) {
    *total_bytes += h->Size();
    if (class_count) {
      for (int cl = 0; cl < Static::num_size_classes(); ++cl) {
        class_count[cl] += h->freelist_length(cl);
      }
    }
  }
}

void ThreadCache::set_overall_thread_cache_size(size_t new_size) {
  // Clip the value to a reasonable range
  size_t min_size = min_per_thread_cache_size_.load(std::memory_order_relaxed);
  if (new_size < min_size) {
    new_size = min_size;
  }
  if (new_size > (1<<30)) new_size = (1<<30);     // Limit to 1GB
  overall_thread_cache_size_ = new_size;

  RecomputePerThreadCacheSize();
}

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/thread_cache.h000066400000000000000000000312101513545575200213550ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Sanjay Ghemawat 

#ifndef TCMALLOC_THREAD_CACHE_H_
#define TCMALLOC_THREAD_CACHE_H_

#include 
#include 
#include                      // for size_t
#include                      // for uint32_t, uint64_t
#include                   // for ssize_t

#include "base/commandlineflags.h"
#include "common.h"
#include "linked_list.h"
#include "page_heap_allocator.h"
#include "sampler.h"
#include "static_vars.h"

#include "common.h"            // for SizeMap, kMaxSize, etc
#include "internal_logging.h"  // for ASSERT, etc
#include "linked_list.h"       // for SLL_Pop, SLL_PopRange, etc
#include "page_heap_allocator.h"  // for PageHeapAllocator
#include "sampler.h"           // for Sampler
#include "static_vars.h"       // for Static

DECLARE_int64(tcmalloc_sample_parameter);

namespace tcmalloc {

//-------------------------------------------------------------------
// Data kept per thread
//-------------------------------------------------------------------

class ThreadCache {
 public:
  // Allocate a new heap. REQUIRES: Static::pageheap_lock is not held.
  static ThreadCache* NewHeap();
  // REQUIRES: Static::pageheap_lock is not held.
  static void DeleteCache(ThreadCache* heap);

  // Accessors (mostly just for printing stats)
  int freelist_length(uint32_t cl) const { return list_[cl].length(); }

  // Total byte size in cache
  size_t Size() const { return size_; }

  // Allocate an object of the given size and class. The size given
  // must be the same as the size of the class in the size map.
  void* Allocate(size_t size, uint32_t cl, void *(*oom_handler)(size_t size));
  void Deallocate(void* ptr, uint32_t size_class);

  void Scavenge();

  int GetSamplePeriod();

  // Record allocation of "k" bytes.  Return true iff allocation
  // should be sampled
  bool SampleAllocation(size_t k);

  bool TryRecordAllocationFast(size_t k);

  static void InitModule();
  static void EnsureMallocInitialized() {
    if (Static::IsInited()) {
      return;
    }
    InitModule();
  }

  // Return the number of thread heaps in use.
  static inline int HeapsInUse();

  // Adds to *total_bytes the total number of bytes used by all thread heaps.
  // Also, if class_count is not nullptr, it must be an array of size kNumClasses,
  // and this function will increment each element of class_count by the number
  // of items in all thread-local freelists of the corresponding size class.
  // REQUIRES: Static::pageheap_lock is held.
  static void GetThreadStats(uint64_t* total_bytes, uint64_t* class_count);

  // Sets the total thread cache size to new_size, recomputing the
  // individual thread cache sizes as necessary.
  // REQUIRES: Static::pageheap lock is held.
  static void set_overall_thread_cache_size(size_t new_size);
  static size_t overall_thread_cache_size() {
    return overall_thread_cache_size_;
  }

  // Sets the lower bound on per-thread cache size to new_size.
  static void set_min_per_thread_cache_size(size_t new_size) {
    min_per_thread_cache_size_.store(new_size, std::memory_order_relaxed);
  }

  static size_t min_per_thread_cache_size() {
    return min_per_thread_cache_size_.load(std::memory_order_relaxed);
  }

  static int thread_heap_count() {
    return thread_heap_count_;
  }

 private:
  class FreeList {
   private:
    void*    list_;       // Linked list of nodes

#ifdef _LP64
    // On 64-bit hardware, manipulating 16-bit values may be slightly slow.
    uint32_t length_;      // Current length.
    uint32_t lowater_;     // Low water mark for list length.
    uint32_t max_length_;  // Dynamic max list length based on usage.
    // Tracks the number of times a deallocation has caused
    // length_ > max_length_.  After the kMaxOverages'th time, max_length_
    // shrinks and length_overages_ is reset to zero.
    uint32_t length_overages_;
#else
    // If we aren't using 64-bit pointers then pack these into less space.
    uint16_t length_;
    uint16_t lowater_;
    uint16_t max_length_;
    uint16_t length_overages_;
#endif

    int32_t size_;

   public:
    void Init(size_t size) {
      list_ = nullptr;
      length_ = 0;
      lowater_ = 0;
      max_length_ = 1;
      length_overages_ = 0;
      size_ = size;
    }

    // Return current length of list
    size_t length() const {
      return length_;
    }

    int32_t object_size() const {
      return size_;
    }

    // Return the maximum length of the list.
    size_t max_length() const {
      return max_length_;
    }

    // Set the maximum length of the list.  If 'new_max' > length(), the
    // client is responsible for removing objects from the list.
    void set_max_length(size_t new_max) {
      max_length_ = new_max;
    }

    // Return the number of times that length() has gone over max_length().
    size_t length_overages() const {
      return length_overages_;
    }

    void set_length_overages(size_t new_count) {
      length_overages_ = new_count;
    }

    // Is list empty?
    bool empty() const {
      return list_ == nullptr;
    }

    // Low-water mark management
    int lowwatermark() const { return lowater_; }
    void clear_lowwatermark() { lowater_ = length_; }

    uint32_t Push(void* ptr) {
      uint32_t length = length_ + 1;
      SLL_Push(&list_, ptr);
      length_ = length;
      return length;
    }

    void* Pop() {
      ASSERT(list_ != nullptr);
      length_--;
      if (length_ < lowater_) lowater_ = length_;
      return SLL_Pop(&list_);
    }

    bool TryPop(void **rv) {
      if (SLL_TryPop(&list_, rv)) {
        length_--;
        if (PREDICT_FALSE(length_ < lowater_)) lowater_ = length_;
        return true;
      }
      return false;
    }

    void* Next() {
      return SLL_Next(&list_);
    }

    void PushRange(int N, void *start, void *end) {
      SLL_PushRange(&list_, start, end);
      length_ += N;
    }

    void PopRange(int N, void **start, void **end) {
      SLL_PopRange(&list_, N, start, end);
      ASSERT(length_ >= N);
      length_ -= N;
      if (length_ < lowater_) lowater_ = length_;
    }
  };

  // REQUIRES: Static::pageheap_lock is held
  ThreadCache();
  // REQUIRES: Static::pageheap_lock is not held
  ~ThreadCache();

  // Gets and returns an object from the central cache, and, if possible,
  // also adds some objects of that size class to this thread cache.
  void* FetchFromCentralCache(uint32_t cl, int32_t byte_size,
                              void *(*oom_handler)(size_t size));

  void ListTooLong(void* ptr, uint32_t cl);

  // Releases some number of items from src.  Adjusts the list's max_length
  // to eventually converge on num_objects_to_move(cl).
  void ListTooLong(FreeList* src, uint32_t cl);

  // Releases N items from this thread cache.
  void ReleaseToCentralCache(FreeList* src, uint32_t cl, int N);

  void SetMaxSize(int32_t new_max_size);

  // Increase max_size_ by reducing unclaimed_cache_space_ or by
  // reducing the max_size_ of some other thread.  In both cases,
  // the delta is kStealAmount.
  void IncreaseCacheLimit();
  // Same as above but requires Static::pageheap_lock() is held.
  void IncreaseCacheLimitLocked();

  // Linked list of heap objects.  Protected by Static::pageheap_lock.
  static ThreadCache* thread_heaps_;
  static int thread_heap_count_;

  // A pointer to one of the objects in thread_heaps_.  Represents
  // the next ThreadCache from which a thread over its max_size_ should
  // steal memory limit.  Round-robin through all of the objects in
  // thread_heaps_.  Protected by Static::pageheap_lock.
  static ThreadCache* next_memory_steal_;

  // Lower bound on per thread cache size. Default value is 512 KBs. 
  static std::atomic min_per_thread_cache_size_;

  // Overall thread cache size.  Protected by Static::pageheap_lock.
  static size_t overall_thread_cache_size_;

  // Global per-thread cache size.  Writes are protected by
  // Static::pageheap_lock.  Reads are done without any locking, which should be
  // fine as long as size_t can be written atomically and we don't place
  // invariants between this variable and other pieces of state.
  static volatile size_t per_thread_cache_size_;

  // Represents overall_thread_cache_size_ minus the sum of max_size_
  // across all ThreadCaches.  Protected by Static::pageheap_lock.
  static ssize_t unclaimed_cache_space_;

  // This class is laid out with the most frequently used fields
  // first so that hot elements are placed on the same cache line.

  FreeList      list_[kClassSizesMax];     // Array indexed by size-class

  int32_t       size_;                     // Combined size of data
  int32_t       max_size_;                 // size_ > max_size_ --> Scavenge()

  // We sample allocations, biased by the size of the allocation
  Sampler       sampler_;               // A sampler

  static void RecomputePerThreadCacheSize();

  // All ThreadCache objects are kept in a linked list (for stats collection)
  ThreadCache* next_;
  ThreadCache* prev_;

  // Ensure that this class is cacheline-aligned. This is critical for
  // performance, as false sharing would negate many of the benefits
  // of a per-thread cache.
} CACHELINE_ALIGNED;

// Allocator for thread heaps
// This is logically part of the ThreadCache class, but MSVC, at
// least, does not like using ThreadCache as a template argument
// before the class is fully defined.  So we put it outside the class.
extern PageHeapAllocator threadcache_allocator;

inline int ThreadCache::HeapsInUse() {
  return threadcache_allocator.inuse();
}

ALWAYS_INLINE void* ThreadCache::Allocate(
  size_t size, uint32_t cl, void *(*oom_handler)(size_t size)) {
  FreeList* list = &list_[cl];

#ifdef NO_TCMALLOC_SAMPLES
  size = list->object_size();
#endif

  ASSERT(size <= kMaxSize);
  ASSERT(size != 0);
  ASSERT(size == 0 || size == Static::sizemap()->ByteSizeForClass(cl));

  void* rv;
  if (!list->TryPop(&rv)) {
    return FetchFromCentralCache(cl, size, oom_handler);
  }
  size_ -= size;
  return rv;
}

ALWAYS_INLINE void ThreadCache::Deallocate(void* ptr, uint32_t cl) {
  ASSERT(list_[cl].max_length() > 0);
  FreeList* list = &list_[cl];

  // This catches back-to-back frees of allocs in the same size
  // class. A more comprehensive (and expensive) test would be to walk
  // the entire freelist. But this might be enough to find some bugs.
  ASSERT(ptr != list->Next());

  uint32_t length = list->Push(ptr);

  if (PREDICT_FALSE(length > list->max_length())) {
    ListTooLong(list, cl);
    return;
  }

  size_ += list->object_size();
  if (PREDICT_FALSE(size_ > max_size_)){
    Scavenge();
  }
}

inline void ThreadCache::SetMaxSize(int32_t new_max_size) {
  max_size_ = new_max_size;
}

#ifndef NO_TCMALLOC_SAMPLES

inline bool ThreadCache::SampleAllocation(size_t k) {
  ASSERT(Static::IsInited());
  return !sampler_.RecordAllocation(k);
}

inline bool ThreadCache::TryRecordAllocationFast(size_t k) {
  ASSERT(Static::IsInited());
  return sampler_.TryRecordAllocationFast(k);
}

#else

inline bool ThreadCache::SampleAllocation(size_t k) {
  return false;
}

inline bool ThreadCache::TryRecordAllocationFast(size_t k) {
  return true;
}

#endif

}  // namespace tcmalloc

#endif  // TCMALLOC_THREAD_CACHE_H_
gperftools-gperftools-2.18/src/thread_cache_ptr.cc000066400000000000000000000315641513545575200224140ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "thread_cache_ptr.h"

#include "common.h"

namespace tcmalloc {

/* static */
TlsKey ThreadCachePtr::tls_key_ = kInvalidTLSKey;

// SlowTLS implements slow-but-safe thread-local facility. It maps
// threads to pairs of ThreadCache and emergency malloc mode flag.
//
// We use it in places where we cannot safely use "normal" TLS
// facility (due to recursion-into-malloc concerns).  Strictly
// speaking, it is only necessary for !kHaveGoodTLS systems. But since
// we want to avoid too much divergency between those 2 classes of
// systems, we also have even good-tls systems use this facility.
//
// We use it for early stage of process lifetime (before we're sure it
// is safe to initialize pthread_{set,get}specific key). We also use
// early in thread's thread cache initialization around the call to
// pthread_setspecific (which in some implementations occasionally
// recurses back to malloc). And we use it for StacktraceScope
// lifetimes to signal emergency malloc mode.
//
// The implementation uses small fixed-size hash table keyed by
// SelfThreadId into Entry structs which contain pointer and bool.
class SlowTLS {
public:
  struct Entry {
    ThreadCache* const cache;
    bool emergency_malloc{};
    bool was_allocated{};

    explicit Entry(ThreadCache* cache) : cache(cache) {}

    Entry(const Entry&) = delete;
    Entry& operator=(const Entry&) = delete;

    void DebugDirty() {
#ifndef NDEBUG
      memset(this, 0xff, sizeof(*this));
#endif
    }

  private:
    friend class SlowTLS;
    uintptr_t thread_id;
    Entry* next;
    Entry** prev;
  };

  class Result {
  public:
    bool Found() const {
      return entry_ != nullptr;
    }
    bool IsEmergencyMalloc() const {
      return entry_->emergency_malloc;
    }
    ThreadCache* GetCache() const {
      return entry_->cache;
    }
    Entry* GetEntry() const {
      return entry_;
    }
  private:
    Result(uintptr_t thread_id, Entry** ht_place, Entry* entry)
      : thread_id_(thread_id), ht_place_(ht_place), entry_(entry) {}

    friend class SlowTLS;

    const uintptr_t thread_id_;
    Entry** const ht_place_;
    Entry* const entry_;
  };

  static Result Lookup() {
    uintptr_t thread_id;
#if defined(__FreeBSD__) || defined(__NetBSD__)
    const bool kIsBSD = true;
#else
    const bool kIsBSD = false;
#endif
    if constexpr (kHaveGoodTLS || kIsBSD) {
      // SelfThreadId is a working, mostly portable and recursion-free
      // thread identifier.
      //
      // However, on FreeBSD and NetBSD thread's errno location for
      // initial thread changes early during process
      // initialization. As runtime facility "switches" from single
      // threaded "mode" to multi-threaded. IMHO a tiny mistake on
      // their part, it adds small overhead too. Outcome is, if we use
      // errno location, we then "leak" very first thread cache
      // instance. Not a disaster, but not great. And
      // thread_dealloc_unittest catches this too. So lets fix it and
      // have tests pass. Other OSes might do the same, but I checked
      // opensolaris, osex, all Linux libc-s, they're all good.
      //
      // Both those BSDs have great Elf-based TLS which also covers
      // this early usage case too. And since it is faster too (no
      // need to call __error or __errno_location), lets use it on all
      // "good-TLS" platforms. We already have tls_data_, so lets use
      // it's address.
      thread_id = reinterpret_cast(&ThreadCachePtr::tls_data_);
    } else {
      thread_id = SelfThreadId();
    }
    Entry** ht_place = &hash_table_[std::hash{}(thread_id) % kTableSize];

    SpinLockHolder h(&lock_);

    for (Entry* entry = *ht_place; entry != nullptr; entry = entry->next) {
      if (entry->thread_id == thread_id) {
        return Result{thread_id, ht_place, entry};
      }
    }

    return Result{thread_id, ht_place, nullptr};
  }

  static ThreadCache* TryToReleaseCacheFromAllocation(Result* result) {
    Entry* entry = result->entry_;

    // GetSlow deals with emergency_malloc case before it calling us.
    ASSERT(!entry->emergency_malloc);

    if (PREDICT_FALSE(entry->was_allocated) && ThreadCachePtr::ThreadCacheKeyIsReady()) {
      ThreadCache* cache = entry->cache;

      SlowTLS::UnregisterEntry(entry);

      return cache;
    }

    return nullptr;
  }

  static void RegisterEntry(Result* result, Entry* entry) {
    entry->thread_id = result->thread_id_;
    entry->prev = result->ht_place_;

    SpinLockHolder h(&lock_);

    Entry* next = entry->next = *result->ht_place_;
    if (next) {
      ASSERT(next->prev == result->ht_place_);
      next->prev = &entry->next;
    }
    *result->ht_place_ = entry;
  }

  static void UnregisterEntry(Entry* entry) {
    SpinLockHolder h(&lock_);
    ASSERT(*entry->prev == entry);
    Entry* next = *entry->prev = entry->next;
    if (next) {
      ASSERT(next->prev == &entry->next);
      next->prev = entry->prev;
    }
    entry->DebugDirty();
  }

  static SpinLock* GetLock() { return &lock_; }

private:
  static constexpr inline int kTableSize = 257;
  static inline Entry* hash_table_[kTableSize];
  static inline SpinLock lock_;
};

/* static */
ThreadCachePtr ThreadCachePtr::GetSlow() {
  // We're being called after GetIfPresent found no cache in normal
  // TLS storage.
  ASSERT(GetIfPresent() == nullptr);

  SlowTLS::Result tr = SlowTLS::Lookup();

  ThreadCache* cache;

  if (tr.Found()) {
    if (tr.IsEmergencyMalloc()) {
      return {nullptr, true};
    }

    // We found TLS entry with our cache. Lets check if we want try
    // convert this cache from pre-tls-ready mode to proper one.
    cache = SlowTLS::TryToReleaseCacheFromAllocation(&tr);
    if (cache == nullptr) {
      // If not, then we return the cache we got in the entry. This
      // must be thread cache instance being set inside ongoing
      // SetTlsValue.
      return {tr.GetCache(), false};
    }
  } else {
    if (!ThreadCacheKeyIsReady()) {
      return GetReallySlow();
    }
    // We're sure that everything is initialized enough to not just
    // create new ThreadCache instance, but to set it into TLS
    // storage.
    cache = ThreadCache::NewHeap();
  }

  SlowTLS::Entry registration{cache};

  // Register our newly created (or extracted from
  // TryToReleaseCacheFromAllocation) cache instance in slow
  // storage. So that if SetTlsValue below recurses back into malloc,
  // we're able to find it and avoid more SetTlsValue
  // recursion.
  SlowTLS::RegisterEntry(&tr, ®istration);

  SetTlsValue(tls_key_, cache);

  SlowTLS::UnregisterEntry(®istration);

  // Note, we could set it before SetTlsValue above and actually
  // prevent any risk of SetTlsValue recursion. But since we want to
  // ensure test coverage for somewhat less common !kHaveGoodTLS
  // systems, lets have "good" systems run the "bad systems'" logic
  // too. For test coverage. Very slight performance hit for of the
  // SlowTLS registration for newly created threads we can afford.
  if constexpr (kHaveGoodTLS) {
    tls_data_.fast_path_cache = cache;
  }

  return {cache, false};
}

/* static */ ATTRIBUTE_NOINLINE
ThreadCachePtr ThreadCachePtr::GetReallySlow() {
  // This is called after we found no cache in regular TLS storage and
  // that TLS storage key isn't set up yet. I.e. process is running,
  // but not all C++ initializers (in this specific case,
  // InitThreadCachePtrLate) ran yet.
  //
  // Not just only that, but we might be dealing with entirely
  // uninitialized malloc. So we handle that first.
  ThreadCache::InitModule();

  // InitModule does some locking (and super-unlikely, but not
  // impossibly, some sleeping). Also it runs some malloc as well
  // (e.g. for pthread_atfork). So here we might actually find
  // thread's cache to be present.

  SlowTLS::Result tr = SlowTLS::Lookup();

  if (tr.Found()) {
    return {tr.GetCache(), tr.IsEmergencyMalloc()};
  }

  ThreadCache* cache = ThreadCache::NewHeap();

  // Note, we allocate slow tls registration and "leak" it. We expect
  // just single thread (initial thread) in most common cases. And
  // maybe, very rarely several. So leaking a little memory is totally
  // harmless. After all, it is our general approach to never free
  // metadata allocations. Plus, those threads that are either initial
  // thread or are allocated before program's main() tend to live
  // forever anyways.
  void* memory = MetaDataAlloc(sizeof(SlowTLS::Entry));
  SlowTLS::Entry* allocated_registration = new (memory) SlowTLS::Entry{cache};
  allocated_registration->was_allocated = true;

  SlowTLS::RegisterEntry(&tr, allocated_registration);

  return {cache, false};
}

/* static */
void ThreadCachePtr::ClearCacheTLS() {
  if constexpr (kHaveGoodTLS) {
    tls_data_.fast_path_cache = nullptr;
  }
}

/* static */
ThreadCache* ThreadCachePtr::ReleaseAndClear() {
  ThreadCache* cache = GetIfPresent();

  if (cache) {
    ClearCacheTLS();
    SetTlsValue(tls_key_, nullptr);
  }
  return cache;
}

/* static */
void ThreadCachePtr::InitThreadCachePtrLate() {
  ASSERT(tls_key_ == kInvalidTLSKey);

  ThreadCache::InitModule();

#if !defined(NDEBUG) && defined(__GLIBC__)
  if constexpr (!kHaveGoodTLS) {
    // Lets force glibc to exercise SetTlsValue recursion case (in
    // GetSlow) in debug mode. For test coverage.
    TlsKey leaked;
    for (int i = 32; i > 0; i--) {
      CreateTlsKey(&leaked, nullptr);
    }
  }
#endif // !NDEBUG

  // NOTE: creating tls key is likely to recurse into malloc. So this
  // is "late" initialization. And we must not mark tls initialized
  // until this is complete.
  int err = CreateTlsKey(&tls_key_, +[] (void *ptr) -> void {
    ClearCacheTLS();

    ThreadCache::DeleteCache(static_cast(ptr));
  });
  CHECK(err == 0);
}

SpinLock* ThreadCachePtr::GetSlowTLSLock() {
  return SlowTLS::GetLock();
}

#if defined(ENABLE_EMERGENCY_MALLOC)

/* static */ ATTRIBUTE_NOINLINE
void ThreadCachePtr::WithStacktraceScope(void (*fn)(bool stacktrace_allowed, void* arg), void* arg) {
  SlowTLS::Result tr = SlowTLS::Lookup();

  SlowTLS::Entry* entry = tr.GetEntry();
  if (entry) {
    if (entry->emergency_malloc) {
      return fn(false, arg);
    }

    ASSERT(GetIfPresent() == nullptr);

    // We have existing entry. Likely "was_allocated" entry. We just
    // mark emergency_malloc in the entry for the duration of the
    // call.
    //
    // Also note, that emergency_malloc Entry cannot be "released" by
    // GetSlow logic (we check emergency malloc mode first).
    entry->emergency_malloc = true;
    fn(true, arg);
    entry->emergency_malloc = false;

    return;
  }

  // If there is currently active ThreadCache for this thread, lets
  // make sure we capture it in our registration.
  SlowTLS::Entry registration{GetIfPresent()};
  registration.emergency_malloc = true;

  SlowTLS::RegisterEntry(&tr, ®istration);

  if (registration.cache != nullptr) {
    // Holds iff we don't touch fast_path_cache until tls is ready as
    // currently written.
    ASSERT(ThreadCacheKeyIsReady());
    if constexpr (kHaveGoodTLS) {
      tls_data_.fast_path_cache = nullptr;
    }
    SetTlsValue(tls_key_, nullptr);
  }

  fn(true, arg);

  if (registration.cache != nullptr) {
    SetTlsValue(tls_key_, registration.cache);
    if constexpr (kHaveGoodTLS) {
      tls_data_.fast_path_cache = registration.cache;
    }
  }
  SlowTLS::UnregisterEntry(®istration);
}

#endif  // ENABLE_EMERGENCY_MALLOC

}  // namespace tcmalloc
gperftools-gperftools-2.18/src/thread_cache_ptr.h000066400000000000000000000127321513545575200222520ustar00rootroot00000000000000/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
 * Copyright (c) 2024, gperftools Contributors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef THREAD_CACHE_PTR_H_
#define THREAD_CACHE_PTR_H_
#include "config.h"

#include "base/basictypes.h"
#include "base/function_ref.h"
#include "base/spinlock.h"
#include "base/threading.h"
#include "thread_cache.h"

// This module encapsulates tcmalloc's thread cache access. Including
// fast-path access, early access (when process is too young and TLS
// facility isn't set up yet) and emergency malloc mode signaling.

namespace tcmalloc {

// Those platforms are known to do emutls or similar for TLS
// implementation. And so, we have to be more careful especially early
// in process lifetime.
#if __MINGW32__
// There is no better test sadly, but clang mingw builds that use
// libc++ (and target ucrt) end up with proper support for tls (and
// don't depend on windpthreads too). Other mingws we assume to be emutls
#if !defined(_LIBCPP_VERSION)
#define MINGW_WITH_BAD_TLS 1
#endif
#endif
#if __QNXNTO__ || __APPLE__ || MINGW_WITH_BAD_TLS || _AIX || TCMALLOC_FORCE_BAD_TLS
inline constexpr bool kHaveGoodTLS = false;
#else
// All other platforms are assumed to be great. Known great are
// GNU/Linux (musl too, and android's bionic too, but only most recent
// versions), FreeBSD, NetBSD, Solaris, Windows (but, sadly, not with
// mingw)
inline constexpr bool kHaveGoodTLS = true;
#endif

#if defined(ENABLE_EMERGENCY_MALLOC)
inline constexpr bool kUseEmergencyMalloc = true;
#else
inline constexpr bool kUseEmergencyMalloc = false;
#endif


class ThreadCachePtr {
public:
  static bool ThreadCacheKeyIsReady() {
    return (tls_key_ != kInvalidTLSKey);
  }

  static ThreadCache* GetIfPresent() {
    if constexpr (kHaveGoodTLS) {
      return tls_data_.fast_path_cache;
    }

    if (PREDICT_FALSE(!ThreadCacheKeyIsReady())) {
      return nullptr;
    }
    return static_cast(GetTlsValue(tls_key_));
  }

  static void InitThreadCachePtrLate();

  static ThreadCachePtr Grab() {
    ThreadCache* cache = GetIfPresent();
    if (cache) {
      return {cache, false};
    }

    return GetSlow();
  }

  bool IsEmergencyMallocEnabled() const {
    return kUseEmergencyMalloc && is_emergency_malloc_;
  }

  ThreadCache* get() const { return ptr_; }

  ThreadCache& operator*() const { return *ptr_; }
  ThreadCache* operator->() const { return ptr_; }

  // Cleans up thread's cache pointer and returns what it was. Used by
  // TCMallocImplementation::MarkThreadIdle.
  static ThreadCache* ReleaseAndClear();

  // WithStacktraceScope runs passed function with given arg enabling
  // emergency malloc around that call. If emergency malloc for
  // current thread is already in effect it passes false to
  // stacktrace_allowed argument of `fn'. See malloc_backtrace.cc for
  // it's usage.
  static void WithStacktraceScope(void (*fn)(bool stacktrace_allowed, void* arg), void* arg);

  static void WithStacktraceScope(tcmalloc::FunctionRef body) {
    WithStacktraceScope(body.fn, body.data);
  }

  // For pthread_atfork handler
  static SpinLock* GetSlowTLSLock();

private:
  friend class SlowTLS;

  static ThreadCachePtr GetSlow();
  static ThreadCachePtr GetReallySlow();

  static void ClearCacheTLS();

  ThreadCachePtr(ThreadCache* ptr, bool is_emergency_malloc)
    : ptr_(ptr), is_emergency_malloc_(is_emergency_malloc) {
  }

  struct TLSData {
    ThreadCache* fast_path_cache;
  };

  static inline thread_local TLSData tls_data_ ATTR_INITIAL_EXEC;
  static TlsKey tls_key_;

  ThreadCache* const ptr_;
  const bool is_emergency_malloc_;
};


#if !defined(ENABLE_EMERGENCY_MALLOC)
// Note, the "real" implementation for ENABLE_EMERGENCY_MALLOC case is in .cc
inline ATTRIBUTE_NOINLINE
void ThreadCachePtr::WithStacktraceScope(void (*fn)(bool stacktrace_allowed, void* arg), void* arg) {
  fn(true, arg);
  // prevent tail-calling fn.
  (void)*const_cast(reinterpret_cast(arg));
}
#endif // !ENABLE_EMERGENCY_MALLOC

}  // namespace tcmalloc

#endif  // THREAD_CACHE_PTR_H_
gperftools-gperftools-2.18/src/windows/000077500000000000000000000000001513545575200203075ustar00rootroot00000000000000gperftools-gperftools-2.18/src/windows/CMakeLists.txt000066400000000000000000000003321513545575200230450ustar00rootroot00000000000000#enable_language(ASM)
#add_executable(preamble_patcher_test preamble_patcher_test.cc shortproc.asm)
#target_link_libraries(preamble_patcher_test tcmalloc_minimal)
#add_test(preamble_patcher_test preamble_patcher_test)
gperftools-gperftools-2.18/src/windows/auto_testing_hook.h000066400000000000000000000141171513545575200242110ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Utility for using SideStep with unit tests.

#ifndef CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_
#define CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_

#include "base/basictypes.h"
#include "base/logging.h"
#include "preamble_patcher.h"

#define SIDESTEP_CHK(x)  CHECK(x)
#define SIDESTEP_EXPECT_TRUE(x)  SIDESTEP_CHK(x)

namespace sidestep {

// Same trick as common/scope_cleanup.h ScopeGuardImplBase
class AutoTestingHookBase {
 public:
  virtual ~AutoTestingHookBase() {}
};

// This is the typedef you normally use for the class, e.g.
//
// AutoTestingHook hook = MakeTestingHook(TargetFunc, HookTargetFunc);
//
// The 'hook' variable will then be destroyed when it goes out of scope.
//
// NOTE: You must not hold this type as a member of another class.  Its
// destructor will not get called.
typedef const AutoTestingHookBase& AutoTestingHook;

// This is the class you must use when holding a hook as a member of another
// class, e.g.
//
// public:
//  AutoTestingHookHolder holder_;
//  MyClass() : my_hook_holder(MakeTestingHookHolder(Target, Hook)) {}
class AutoTestingHookHolder {
 public:
  explicit AutoTestingHookHolder(AutoTestingHookBase* hook) : hook_(hook) {}
  ~AutoTestingHookHolder() { delete hook_; }
 private:
  AutoTestingHookHolder() {}  // disallow
  AutoTestingHookBase* hook_;
};

// This class helps patch a function, then unpatch it when the object exits
// scope, and also maintains the pointer to the original function stub.
//
// To enable use of the class without having to explicitly provide the
// type of the function pointers (and instead only providing it
// implicitly) we use the same trick as ScopeGuard (see
// common/scope_cleanup.h) uses, so to create a hook you use the MakeHook
// function rather than a constructor.
//
// NOTE:  This function is only safe for e.g. unit tests and _not_ for
// production code.  See PreamblePatcher class for details.
template 
class AutoTestingHookImpl : public AutoTestingHookBase {
 public:
  static AutoTestingHookImpl MakeTestingHook(T target_function,
                                                T replacement_function,
                                                bool do_it) {
    return AutoTestingHookImpl(target_function, replacement_function, do_it);
  }

  static AutoTestingHookImpl* MakeTestingHookHolder(T target_function,
                                                       T replacement_function,
                                                       bool do_it) {
    return new AutoTestingHookImpl(target_function,
                                      replacement_function, do_it);
  }

  ~AutoTestingHookImpl() {
    if (did_it_) {
      SIDESTEP_CHK(SIDESTEP_SUCCESS == PreamblePatcher::Unpatch(
          (void*)target_function_, (void*)replacement_function_,
          (void*)original_function_));
    }
  }

  // Returns a pointer to the original function.  To use this method you will
  // have to explicitly create an AutoTestingHookImpl of the specific
  // function pointer type (i.e. not use the AutoTestingHook typedef).
  T original_function() {
    return original_function_;
  }

 private:
  AutoTestingHookImpl(T target_function, T replacement_function, bool do_it)
      : target_function_(target_function),
        original_function_(nullptr),
        replacement_function_(replacement_function),
        did_it_(do_it) {
    if (do_it) {
      SIDESTEP_CHK(SIDESTEP_SUCCESS == PreamblePatcher::Patch(target_function,
                                                     replacement_function,
                                                     &original_function_));
    }
  }

  T target_function_;  // always valid
  T original_function_;  // always valid
  T replacement_function_;  // always valid
  bool did_it_;  // Remember if we did it or not...
};

template 
inline AutoTestingHookImpl MakeTestingHook(T target,
                                              T replacement,
                                              bool do_it) {
  return AutoTestingHookImpl::MakeTestingHook(target, replacement, do_it);
}

template 
inline AutoTestingHookImpl MakeTestingHook(T target, T replacement) {
  return AutoTestingHookImpl::MakeTestingHook(target, replacement, true);
}

template 
inline AutoTestingHookImpl* MakeTestingHookHolder(T target, T replacement) {
  return AutoTestingHookImpl::MakeTestingHookHolder(target, replacement,
                                                       true);
}

};  // namespace sidestep

#endif  // CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_
gperftools-gperftools-2.18/src/windows/get_mangled_names.cc000066400000000000000000000061101513545575200242450ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Craig Silverstein (opensource@google.com)

// When you are porting perftools to a new compiler or architecture
// (win64 vs win32) for instance, you'll need to change the mangled
// symbol names for operator new and friends at the top of
// patch_functions.cc.  This file helps you do that.
//
// It does this by defining these functions with the proper signature.
// All you need to do is compile this file and the run dumpbin on it.
// (See http://msdn.microsoft.com/en-us/library/5x49w699.aspx for more
// on dumpbin).  To do this in MSVC, use the MSVC commandline shell:
//    http://msdn.microsoft.com/en-us/library/ms235639(VS.80).aspx)
//
// The run:
//    cl /c get_mangled_names.cc
//    dumpbin /symbols get_mangled_names.obj
//
// It will print out the mangled (and associated unmangled) names of
// the 8 symbols you need to put at the top of patch_functions.cc

#include    // for size_t
#include            // for nothrow_t

static char m;   // some dummy memory so new doesn't return nullptr.

void* operator new(size_t size) { return &m; }
void operator delete(void* p) throw() { }
void* operator new[](size_t size) { return &m; }
void operator delete[](void* p) throw() { }

void* operator new(size_t size, const std::nothrow_t&) throw() { return &m; }
void operator delete(void* p, const std::nothrow_t&) throw() { }
void* operator new[](size_t size, const std::nothrow_t&) throw() { return &m; }
void operator delete[](void* p, const std::nothrow_t&) throw() { }
gperftools-gperftools-2.18/src/windows/ia32_modrm_map.cc000066400000000000000000000120731513545575200234120ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 *
 * Table of relevant information about how to decode the ModR/M byte.
 * Based on information in the IA-32 Intel® Architecture
 * Software Developer's Manual Volume 2: Instruction Set Reference.
 */

#include "mini_disassembler.h"
#include "mini_disassembler_types.h"

namespace sidestep {

const ModrmEntry MiniDisassembler::s_ia16_modrm_map_[] = {
// mod == 00
  /* r/m == 000 */ { false, false, OS_ZERO },
  /* r/m == 001 */ { false, false, OS_ZERO },
  /* r/m == 010 */ { false, false, OS_ZERO },
  /* r/m == 011 */ { false, false, OS_ZERO },
  /* r/m == 100 */ { false, false, OS_ZERO },
  /* r/m == 101 */ { false, false, OS_ZERO },
  /* r/m == 110 */ { true, false, OS_WORD },
  /* r/m == 111 */ { false, false, OS_ZERO },
// mod == 01
  /* r/m == 000 */ { true, false, OS_BYTE },
  /* r/m == 001 */ { true, false, OS_BYTE },
  /* r/m == 010 */ { true, false, OS_BYTE },
  /* r/m == 011 */ { true, false, OS_BYTE },
  /* r/m == 100 */ { true, false, OS_BYTE },
  /* r/m == 101 */ { true, false, OS_BYTE },
  /* r/m == 110 */ { true, false, OS_BYTE },
  /* r/m == 111 */ { true, false, OS_BYTE },
// mod == 10
  /* r/m == 000 */ { true, false, OS_WORD },
  /* r/m == 001 */ { true, false, OS_WORD },
  /* r/m == 010 */ { true, false, OS_WORD },
  /* r/m == 011 */ { true, false, OS_WORD },
  /* r/m == 100 */ { true, false, OS_WORD },
  /* r/m == 101 */ { true, false, OS_WORD },
  /* r/m == 110 */ { true, false, OS_WORD },
  /* r/m == 111 */ { true, false, OS_WORD },
// mod == 11
  /* r/m == 000 */ { false, false, OS_ZERO },
  /* r/m == 001 */ { false, false, OS_ZERO },
  /* r/m == 010 */ { false, false, OS_ZERO },
  /* r/m == 011 */ { false, false, OS_ZERO },
  /* r/m == 100 */ { false, false, OS_ZERO },
  /* r/m == 101 */ { false, false, OS_ZERO },
  /* r/m == 110 */ { false, false, OS_ZERO },
  /* r/m == 111 */ { false, false, OS_ZERO }
};

const ModrmEntry MiniDisassembler::s_ia32_modrm_map_[] = {
// mod == 00
  /* r/m == 000 */ { false, false, OS_ZERO },
  /* r/m == 001 */ { false, false, OS_ZERO },
  /* r/m == 010 */ { false, false, OS_ZERO },
  /* r/m == 011 */ { false, false, OS_ZERO },
  /* r/m == 100 */ { false, true, OS_ZERO },
  /* r/m == 101 */ { true, false, OS_DOUBLE_WORD },
  /* r/m == 110 */ { false, false, OS_ZERO },
  /* r/m == 111 */ { false, false, OS_ZERO },
// mod == 01
  /* r/m == 000 */ { true, false, OS_BYTE },
  /* r/m == 001 */ { true, false, OS_BYTE },
  /* r/m == 010 */ { true, false, OS_BYTE },
  /* r/m == 011 */ { true, false, OS_BYTE },
  /* r/m == 100 */ { true, true, OS_BYTE },
  /* r/m == 101 */ { true, false, OS_BYTE },
  /* r/m == 110 */ { true, false, OS_BYTE },
  /* r/m == 111 */ { true, false, OS_BYTE },
// mod == 10
  /* r/m == 000 */ { true, false, OS_DOUBLE_WORD },
  /* r/m == 001 */ { true, false, OS_DOUBLE_WORD },
  /* r/m == 010 */ { true, false, OS_DOUBLE_WORD },
  /* r/m == 011 */ { true, false, OS_DOUBLE_WORD },
  /* r/m == 100 */ { true, true, OS_DOUBLE_WORD },
  /* r/m == 101 */ { true, false, OS_DOUBLE_WORD },
  /* r/m == 110 */ { true, false, OS_DOUBLE_WORD },
  /* r/m == 111 */ { true, false, OS_DOUBLE_WORD },
// mod == 11
  /* r/m == 000 */ { false, false, OS_ZERO },
  /* r/m == 001 */ { false, false, OS_ZERO },
  /* r/m == 010 */ { false, false, OS_ZERO },
  /* r/m == 011 */ { false, false, OS_ZERO },
  /* r/m == 100 */ { false, false, OS_ZERO },
  /* r/m == 101 */ { false, false, OS_ZERO },
  /* r/m == 110 */ { false, false, OS_ZERO },
  /* r/m == 111 */ { false, false, OS_ZERO },
};

};  // namespace sidestep
gperftools-gperftools-2.18/src/windows/ia32_opcode_map.cc000066400000000000000000003364201513545575200235520ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 *
 * Opcode decoding maps.  Based on the IA-32 Intel® Architecture
 * Software Developer's Manual Volume 2: Instruction Set Reference.  Idea
 * for how to lay out the tables in memory taken from the implementation
 * in the Bastard disassembly environment.
 */

#include "mini_disassembler.h"

namespace sidestep {

/*
* This is the first table to be searched; the first field of each
* Opcode in the table is either 0 to indicate you're in the
* right table, or an index to the correct table, in the global
* map g_pentiumOpcodeMap
*/
const Opcode s_first_opcode_byte[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF */ { 1, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x10 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x11 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x12 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x13 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x14 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x15 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x16 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x17 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x18 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x19 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1E */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1F */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x20 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x21 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x22 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x23 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x24 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x25 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x26 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x27 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "daa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x28 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x29 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "das", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x30 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x31 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x32 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x33 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x34 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x35 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x36 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x37 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aaa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x38 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x39 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aas", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
#ifdef _M_X64
  /* REX Prefixes in 64-bit mode. */
  /* 0x40 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x41 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x42 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x43 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x44 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x45 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x46 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x47 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x48 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x49 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4A */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4B */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4C */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4D */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4F */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
#else
  /* 0x40 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x41 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x42 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x43 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x44 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x45 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x46 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x47 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x48 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x49 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
#endif
  /* 0x50 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x51 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x52 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x53 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x54 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x55 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x56 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x57 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x58 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x59 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x60 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x61 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x62 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_A, AM_NOT_USED, "bound", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x63 */ { 0, IT_GENERIC, AM_E | OT_W, AM_G | OT_W, AM_NOT_USED, "arpl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x64 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x65 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x66 */ { 0, IT_PREFIX_OPERAND, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x67 */ { 0, IT_PREFIX_ADDRESS, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x68 */ { 0, IT_GENERIC, AM_I | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x69 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I | OT_V, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6A */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I |  OT_B, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6C */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "insb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6D */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "insd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6E */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X | OT_B, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X | OT_V, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x70 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x71 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x72 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x73 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x74 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x75 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x76 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x77 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x78 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x79 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7A */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7B */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7C */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7D */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7E */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7F */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x80 */ { 2, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x81 */ { 3, IT_REFERENCE, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x82 */ { 4, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x83 */ { 5, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x84 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x85 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x86 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x87 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x88 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x89 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8C */ { 0, IT_GENERIC, AM_E | OT_W, AM_S | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8D */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, "lea", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8E */ { 0, IT_GENERIC, AM_S | OT_W, AM_E | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8F */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x90 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "nop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x91 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x92 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x93 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x94 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x95 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x96 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x97 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x98 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cwde", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x99 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cdq", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9A */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "callf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9B */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wait", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9E */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_O | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_O | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA2 */ { 0, IT_GENERIC, AM_O | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA3 */ { 0, IT_GENERIC, AM_O | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA4 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "movsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA5 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "movsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA6 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "cmpsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA7 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "cmpsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAA */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "stosb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAB */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "stosd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X| OT_B, AM_NOT_USED, "lodsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X| OT_V, AM_NOT_USED, "lodsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAE */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_Y | OT_B, AM_NOT_USED, "scasb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_Y | OT_V, AM_NOT_USED, "scasd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB1 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB2 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB3 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
#ifdef _M_X64
  /* 0xB8 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBA */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBB */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBC */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBE */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
#else
  /* 0xB8 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBA */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBB */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBC */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBE */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
#endif
  /* 0xC0 */ { 6, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC1 */ { 7, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC2 */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC3 */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC4 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "les", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "lds", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC8 */ { 0, IT_GENERIC, AM_I | OT_W, AM_I | OT_B, AM_NOT_USED, "enter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "leave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCA */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCB */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "int3", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCD */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "int", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCE */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "into", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCF */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "iret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD0 */ { 8, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD1 */ { 9, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD2 */ { 10, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD3 */ { 11, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD4 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aam", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD5 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "xlat", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },

  // The following 8 lines would be references to the FPU tables, but we currently
  // do not support the FPU instructions in this disassembler.

  /* 0xD8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xDA */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xDB */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xDC */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xDD */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xDE */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xDF */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },


  /* 0xE0 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE1 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE2 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE3 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jcxz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE6 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE7 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE8 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE9 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xEA */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xEB */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xEC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xED */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xEE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xEF */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_V, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF0 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lock:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF2 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "repne:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF3 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rep:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF4 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "hlt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF6 */ { 12, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF7 */ { 13, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xFA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cli", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xFB */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xFC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xFD */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "std", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xFE */ { 14, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xFF */ { 15, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_0f[] = {
  /* 0x0 */ { 16, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 17, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lsl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "invd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wbinvd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud2", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xE */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x10 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movups", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "movsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "movss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movupd" } },
  /* 0x11 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movups", true,
    /* F2h */ { 0, IT_GENERIC, AM_W | OT_SD, AM_V | OT_SD, AM_NOT_USED, "movsd" },
    /* F3h */ { 0, IT_GENERIC, AM_W | OT_SS, AM_V | OT_SS, AM_NOT_USED, "movss" },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movupd" } },
  /* 0x12 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" },  // only one of ...
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" },  // ...these two is correct, Intel doesn't specify which
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_S, AM_NOT_USED, "movlpd" } },
  /* 0x13 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlpd" } },
  /* 0x14 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpcklps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpcklpd" } },
  /* 0x15 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpckhps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpckhpd" } },
  /* 0x16 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" },  // only one of...
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" },  // ...these two is correct, Intel doesn't specify which
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhpd" } },
  /* 0x17 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhpd" } },
  /* 0x18 */ { 18, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x19 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1C */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x20 */ { 0, IT_GENERIC, AM_R | OT_D, AM_C | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x21 */ { 0, IT_GENERIC, AM_R | OT_D, AM_D | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x22 */ { 0, IT_GENERIC, AM_C | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x23 */ { 0, IT_GENERIC, AM_D | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x24 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x25 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x26 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x27 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x28 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movaps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movapd" } },
  /* 0x29 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movaps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movapd" } },
  /* 0x2A */ { 0, IT_GENERIC, AM_V | OT_PS, AM_Q | OT_Q, AM_NOT_USED, "cvtpi2ps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_E | OT_D, AM_NOT_USED, "cvtsi2sd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_E | OT_D, AM_NOT_USED, "cvtsi2ss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_Q | OT_DQ, AM_NOT_USED, "cvtpi2pd" } },
  /* 0x2B */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movntps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movntpd" } },
  /* 0x2C */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvttps2pi", true,
    /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvttsd2si" },
    /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvttss2si" },
    /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2pi" } },
  /* 0x2D */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvtps2pi", true,
    /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvtsd2si" },
    /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvtss2si" },
    /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2pi" } },
  /* 0x2E */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "ucomiss", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "ucomisd" } },
  /* 0x2F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_SS, AM_NOT_USED, "comiss", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "comisd" } },
  /* 0x30 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wrmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x31 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdtsc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x32 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x33 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdpmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x34 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysenter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x35 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysexit", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x36 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x37 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x38 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x39 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x40 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x41 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x42 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x43 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x44 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x45 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x46 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x47 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmova", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x48 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x49 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4A */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4D */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4E */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4F */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x50 */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PS, AM_NOT_USED, "movmskps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PD, AM_NOT_USED, "movmskpd" } },
  /* 0x51 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "sqrtps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "sqrtsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "sqrtss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "sqrtpd" } },
  /* 0x52 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rsqrtps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rsqrtss" },
    /* 66h */ { 0 } },
  /* 0x53 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rcpps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rcpss" },
    /* 66h */ { 0 } },
  /* 0x54 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andpd" } },
  /* 0x55 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andnps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andnpd" } },
  /* 0x56 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "orps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "orpd" } },
  /* 0x57 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "xorps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "xorpd" } },
  /* 0x58 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "addps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "addsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "addss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "addpd" } },
  /* 0x59 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "mulps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "mulsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "mulss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "mulpd" } },
  /* 0x5A */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PS, AM_NOT_USED, "cvtps2pd", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "cvtsd2ss" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "cvtss2sd" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PD, AM_NOT_USED, "cvtpd2ps" } },
  /* 0x5B */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2ps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvttps2dq" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvtps2dq" } },
  /* 0x5C */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "subps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "subsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "subss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "subpd" } },
  /* 0x5D */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "minps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "minsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "minss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "minpd" } },
  /* 0x5E */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "divps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "divsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "divss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "divpd" } },
  /* 0x5F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "maxps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "maxsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "maxss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "maxpd" } },
  /* 0x60 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklbw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklbw" } },
  /* 0x61 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklwd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklwd" } },
  /* 0x62 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckldq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpckldq" } },
  /* 0x63 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packsswb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packsswb" } },
  /* 0x64 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtb" } },
  /* 0x65 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtw" } },
  /* 0x66 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtd" } },
  /* 0x67 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packuswb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packuswb" } },
  /* 0x68 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhbw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhbw" } },
  /* 0x69 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhwd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhwd" } },
  /* 0x6A */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhdq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhdq" } },
  /* 0x6B */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packssdw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "packssdw" } },
  /* 0x6C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } },
  /* 0x6D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } },
  /* 0x6E */ { 0, IT_GENERIC, AM_P | OT_D, AM_E | OT_D, AM_NOT_USED, "movd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_NOT_USED, "movd" } },
  /* 0x6F */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "movq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqu" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqa" } },
  /* 0x70 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_I |  OT_B, "pshuf", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshuflw" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufhw" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufd" } },
  /* 0x71 */ { 19, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x72 */ { 20, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x73 */ { 21, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x74 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqb" } },
  /* 0x75 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqw" } },
  /* 0x76 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqd" } },
  /* 0x77 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "emms", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },

  // The following six opcodes are escapes into the MMX stuff, which this disassembler does not support.
  /* 0x78 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x79 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7A */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7B */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7C */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7D */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },

  /* 0x7E */ { 0, IT_GENERIC, AM_E | OT_D, AM_P | OT_D, AM_NOT_USED, "movd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movq" },
    /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_DQ, AM_NOT_USED, "movd" } },
  /* 0x7F */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_P | OT_Q, AM_NOT_USED, "movq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqu" },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqa" } },
  /* 0x80 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x81 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x82 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x83 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x84 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x85 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x86 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x87 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x88 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x89 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8A */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8B */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8C */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8D */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8E */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x8F */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x90 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seto", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x91 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x92 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x93 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x94 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x95 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x96 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x97 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seta", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x98 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "sets", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x99 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9A */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9B */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9C */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9D */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9E */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x9F */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cpuid", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA6 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA7 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rsm", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAC */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAD */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAE */ { 22, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xAF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB2 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lss", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB4 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lfs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB5 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lgs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB6 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB7 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xB9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud1", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBA */ { 23, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBC */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBD */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBE */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xBF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC2 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "cmpps", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_I | OT_B, "cmpsd" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W  | OT_SS, AM_I | OT_B, "cmpss" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "cmppd" } },
  /* 0xC3 */ { 0, IT_GENERIC, AM_E | OT_D, AM_G | OT_D, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_E | OT_D, AM_I | OT_B, "pinsrw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_I | OT_B, "pinsrw" } },
  /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_I | OT_B, "pextrw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_I | OT_B, "pextrw" } },
  /* 0xC6 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "shufps", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "shufpd" } },
  /* 0xC7 */ { 24, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC8 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xC9 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCA */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCB */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCC */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCD */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCE */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xCF */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xD1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlw" } },
  /* 0xD2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrld", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrld" } },
  /* 0xD3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlq" } },
  /* 0xD4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddq" } },
  /* 0xD5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmullw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmullw" } },
  /* 0xD6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "unused without prefix", true,
    /* F2h */ { 0, IT_GENERIC, AM_P | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movdq2q" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_Q | OT_Q, AM_NOT_USED, "movq2dq" },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movq" } },
  /* 0xD7 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_NOT_USED, "pmovmskb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_NOT_USED, "pmovmskb" } },
  /* 0xD8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusb" } },
  /* 0xD9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusw" } },
  /* 0xDA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminub", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminub" } },
  /* 0xDB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pand", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pand" } },
  /* 0xDC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusb" } },
  /* 0xDD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusw" } },
  /* 0xDE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxub", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxub" } },
  /* 0xDF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pandn", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pandn" } },
  /* 0xE0 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgb" } },
  /* 0xE1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psraw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrqw" } },
  /* 0xE2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrad", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrad" } },
  /* 0xE3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgw" } },
  /* 0xE4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhuw" } },
  /* 0xE5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhw" } },
  /* 0xE6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
    /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2dq" },
    /* F3h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2pd" },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2dq" } },
  /* 0xE7 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movntq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movntdq" } },
  /* 0xE8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsb" } },
  /* 0xE9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsw" } },
  /* 0xEA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminsw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminsw" } },
  /* 0xEB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "por", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "por" } },
  /* 0xEC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsb" } },
  /* 0xED */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsw" } },
  /* 0xEE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxsw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxsw" } },
  /* 0xEF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pxor", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pxor" } },
  /* 0xF0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0xF1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllw" } },
  /* 0xF2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pslld", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pslld" } },
  /* 0xF3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllq" } },
  /* 0xF4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmuludq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmuludq" } },
  /* 0xF5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaddwd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaddwd" } },
  /* 0xF6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psadbw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psadbw" } },
  /* 0xF7 */ { 0, IT_GENERIC, AM_P | OT_PI, AM_Q | OT_PI, AM_NOT_USED, "maskmovq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "maskmovdqu" } },
  /* 0xF8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubb" } },
  /* 0xF9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubw" } },
  /* 0xFA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubd" } },
  /* 0xFB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubq" } },
  /* 0xFC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddb", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddb" } },
  /* 0xFD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddw" } },
  /* 0xFE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddd", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddd" } },
  /* 0xFF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_0f00[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "sldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "str", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "ltr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_0f01[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "smsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lmsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_M | OT_B, AM_NOT_USED, AM_NOT_USED, "invlpg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_0f18[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_0f71[] = {
  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlw" } },
  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psraw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psraw" } },
  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllw", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllw" } },
  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_0f72[] = {
  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrld", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrld" } },
  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrad", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrad" } },
  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "pslld", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslld" } },
  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_0f73[] = {
  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlq" } },
  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllq" } },
  /* 0x7 */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq", true,
    /* F2h */ { 0 },
    /* F3h */ { 0 },
    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq" } },
};

const Opcode s_opcode_byte_after_0fae[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxsave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxrstor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ldmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "mfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clflush/sfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
};

const Opcode s_opcode_byte_after_0fba[] = {
  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_0fc7[] = {
  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_Q, AM_NOT_USED, AM_NOT_USED, "cmpxch8b", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_80[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_81[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_82[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_83[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_c0[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_c1[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_d0[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_d1[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_d2[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_d3[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_f6[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_f7[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_fe[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

const Opcode s_opcode_byte_after_ff[] = {
  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x2 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x3 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x4 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x5 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
};

/*
* A table of all the other tables, containing some extra information, e.g.
* how to mask out the byte we're looking at.
*/
const OpcodeTable MiniDisassembler::s_ia32_opcode_map_[]={
  // One-byte opcodes and jumps to larger
  /*  0 */ {s_first_opcode_byte, 0, 0xff, 0, 0xff},
  // Two-byte opcodes (second byte)
  /*  1 */ {s_opcode_byte_after_0f, 0, 0xff, 0, 0xff},
  // Start of tables for opcodes using ModR/M bits as extension
  /*  2 */ {s_opcode_byte_after_80, 3, 0x07, 0, 0x07},
  /*  3 */ {s_opcode_byte_after_81, 3, 0x07, 0, 0x07},
  /*  4 */ {s_opcode_byte_after_82, 3, 0x07, 0, 0x07},
  /*  5 */ {s_opcode_byte_after_83, 3, 0x07, 0, 0x07},
  /*  6 */ {s_opcode_byte_after_c0, 3, 0x07, 0, 0x07},
  /*  7 */ {s_opcode_byte_after_c1, 3, 0x07, 0, 0x07},
  /*  8 */ {s_opcode_byte_after_d0, 3, 0x07, 0, 0x07},
  /*  9 */ {s_opcode_byte_after_d1, 3, 0x07, 0, 0x07},
  /* 10 */ {s_opcode_byte_after_d2, 3, 0x07, 0, 0x07},
  /* 11 */ {s_opcode_byte_after_d3, 3, 0x07, 0, 0x07},
  /* 12 */ {s_opcode_byte_after_f6, 3, 0x07, 0, 0x07},
  /* 13 */ {s_opcode_byte_after_f7, 3, 0x07, 0, 0x07},
  /* 14 */ {s_opcode_byte_after_fe, 3, 0x07, 0, 0x01},
  /* 15 */ {s_opcode_byte_after_ff, 3, 0x07, 0, 0x07},
  /* 16 */ {s_opcode_byte_after_0f00, 3, 0x07, 0, 0x07},
  /* 17 */ {s_opcode_byte_after_0f01, 3, 0x07, 0, 0x07},
  /* 18 */ {s_opcode_byte_after_0f18, 3, 0x07, 0, 0x07},
  /* 19 */ {s_opcode_byte_after_0f71, 3, 0x07, 0, 0x07},
  /* 20 */ {s_opcode_byte_after_0f72, 3, 0x07, 0, 0x07},
  /* 21 */ {s_opcode_byte_after_0f73, 3, 0x07, 0, 0x07},
  /* 22 */ {s_opcode_byte_after_0fae, 3, 0x07, 0, 0x07},
  /* 23 */ {s_opcode_byte_after_0fba, 3, 0x07, 0, 0x07},
  /* 24 */ {s_opcode_byte_after_0fc7, 3, 0x07, 0, 0x01}
};

};  // namespace sidestep
gperftools-gperftools-2.18/src/windows/mini_disassembler.cc000066400000000000000000000372621513545575200243210ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 *
 * Implementation of MiniDisassembler.
 */

#include "mini_disassembler.h"

namespace sidestep {

MiniDisassembler::MiniDisassembler(bool operand_default_is_32_bits,
                                   bool address_default_is_32_bits)
    : operand_default_is_32_bits_(operand_default_is_32_bits),
      address_default_is_32_bits_(address_default_is_32_bits) {
  Initialize();
}

MiniDisassembler::MiniDisassembler()
    : operand_default_is_32_bits_(true),
      address_default_is_32_bits_(true) {
  Initialize();
}

InstructionType MiniDisassembler::Disassemble(
    unsigned char* start_byte,
    unsigned int& instruction_bytes) {
  // Clean up any state from previous invocations.
  Initialize();

  // Start by processing any prefixes.
  unsigned char* current_byte = start_byte;
  unsigned int size = 0;
  InstructionType instruction_type = ProcessPrefixes(current_byte, size);

  if (IT_UNKNOWN == instruction_type)
    return instruction_type;

  current_byte += size;
  size = 0;

  // Invariant: We have stripped all prefixes, and the operand_is_32_bits_
  // and address_is_32_bits_ flags are correctly set.

  instruction_type = ProcessOpcode(current_byte, 0, size);

  // Check for error processing instruction
  if ((IT_UNKNOWN == instruction_type_) || (IT_UNUSED == instruction_type_)) {
    return IT_UNKNOWN;
  }

  current_byte += size;

  // Invariant: operand_bytes_ indicates the total size of operands
  // specified by the opcode and/or ModR/M byte and/or SIB byte.
  // pCurrentByte points to the first byte after the ModR/M byte, or after
  // the SIB byte if it is present (i.e. the first byte of any operands
  // encoded in the instruction).

  // We get the total length of any prefixes, the opcode, and the ModR/M and
  // SIB bytes if present, by taking the difference of the original starting
  // address and the current byte (which points to the first byte of the
  // operands if present, or to the first byte of the next instruction if
  // they are not).  Adding the count of bytes in the operands encoded in
  // the instruction gives us the full length of the instruction in bytes.
  instruction_bytes += operand_bytes_ + (current_byte - start_byte);

  // Return the instruction type, which was set by ProcessOpcode().
  return instruction_type_;
}

void MiniDisassembler::Initialize() {
  operand_is_32_bits_ = operand_default_is_32_bits_;
  address_is_32_bits_ = address_default_is_32_bits_;
#ifdef _M_X64
  operand_default_support_64_bits_ = true;
#else
  operand_default_support_64_bits_ = false;
#endif
  operand_is_64_bits_ = false;
  operand_bytes_ = 0;
  have_modrm_ = false;
  should_decode_modrm_ = false;
  instruction_type_ = IT_UNKNOWN;
  got_f2_prefix_ = false;
  got_f3_prefix_ = false;
  got_66_prefix_ = false;
}

InstructionType MiniDisassembler::ProcessPrefixes(unsigned char* start_byte,
                                                  unsigned int& size) {
  InstructionType instruction_type = IT_GENERIC;
  const Opcode& opcode = s_ia32_opcode_map_[0].table_[*start_byte];

  switch (opcode.type_) {
    case IT_PREFIX_ADDRESS:
      address_is_32_bits_ = !address_default_is_32_bits_;
      goto nochangeoperand;
    case IT_PREFIX_OPERAND:
      operand_is_32_bits_ = !operand_default_is_32_bits_;
      nochangeoperand:
    case IT_PREFIX:

      if (0xF2 == (*start_byte))
        got_f2_prefix_ = true;
      else if (0xF3 == (*start_byte))
        got_f3_prefix_ = true;
      else if (0x66 == (*start_byte))
        got_66_prefix_ = true;
      else if (operand_default_support_64_bits_ && (*start_byte) & 0x48)
        operand_is_64_bits_ = true;

      instruction_type = opcode.type_;
      size ++;
      // we got a prefix, so add one and check next byte
      ProcessPrefixes(start_byte + 1, size);
    default:
      break;   // not a prefix byte
  }

  return instruction_type;
}

InstructionType MiniDisassembler::ProcessOpcode(unsigned char* start_byte,
                                                unsigned int table_index,
                                                unsigned int& size) {
  const OpcodeTable& table = s_ia32_opcode_map_[table_index];   // Get our table
  unsigned char current_byte = (*start_byte) >> table.shift_;
  current_byte = current_byte & table.mask_;  // Mask out the bits we will use

  // Check whether the byte we have is inside the table we have.
  if (current_byte < table.min_lim_ || current_byte > table.max_lim_) {
    instruction_type_ = IT_UNKNOWN;
    return instruction_type_;
  }

  const Opcode& opcode = table.table_[current_byte];
  if (IT_UNUSED == opcode.type_) {
    // This instruction is not used by the IA-32 ISA, so we indicate
    // this to the user.  Probably means that we were pointed to
    // a byte in memory that was not the start of an instruction.
    instruction_type_ = IT_UNUSED;
    return instruction_type_;
  } else if (IT_REFERENCE == opcode.type_) {
    // We are looking at an opcode that has more bytes (or is continued
    // in the ModR/M byte).  Recursively find the opcode definition in
    // the table for the opcode's next byte.
    size++;
    ProcessOpcode(start_byte + 1, opcode.table_index_, size);
    return instruction_type_;
  }

  const SpecificOpcode* specific_opcode = (SpecificOpcode*)&opcode;
  if (opcode.is_prefix_dependent_) {
    if (got_f2_prefix_ && opcode.opcode_if_f2_prefix_.mnemonic_ != 0) {
      specific_opcode = &opcode.opcode_if_f2_prefix_;
    } else if (got_f3_prefix_ && opcode.opcode_if_f3_prefix_.mnemonic_ != 0) {
      specific_opcode = &opcode.opcode_if_f3_prefix_;
    } else if (got_66_prefix_ && opcode.opcode_if_66_prefix_.mnemonic_ != 0) {
      specific_opcode = &opcode.opcode_if_66_prefix_;
    }
  }

  // Inv: The opcode type is known.
  instruction_type_ = specific_opcode->type_;

  // Let's process the operand types to see if we have any immediate
  // operands, and/or a ModR/M byte.

  ProcessOperand(specific_opcode->flag_dest_);
  ProcessOperand(specific_opcode->flag_source_);
  ProcessOperand(specific_opcode->flag_aux_);

  // Inv: We have processed the opcode and incremented operand_bytes_
  // by the number of bytes of any operands specified by the opcode
  // that are stored in the instruction (not registers etc.).  Now
  // we need to return the total number of bytes for the opcode and
  // for the ModR/M or SIB bytes if they are present.

  if (table.mask_ != 0xff) {
    if (have_modrm_) {
      // we're looking at a ModR/M byte so we're not going to
      // count that into the opcode size
      ProcessModrm(start_byte, size);
      return IT_GENERIC;
    } else {
      // need to count the ModR/M byte even if it's just being
      // used for opcode extension
      size++;
      return IT_GENERIC;
    }
  } else {
    if (have_modrm_) {
      // The ModR/M byte is the next byte.
      size++;
      ProcessModrm(start_byte + 1, size);
      return IT_GENERIC;
    } else {
      size++;
      return IT_GENERIC;
    }
  }
}

bool MiniDisassembler::ProcessOperand(int flag_operand) {
  bool succeeded = true;
  if (AM_NOT_USED == flag_operand)
    return succeeded;

  // Decide what to do based on the addressing mode.
  switch (flag_operand & AM_MASK) {
    // No ModR/M byte indicated by these addressing modes, and no
    // additional (e.g. immediate) parameters.
    case AM_A: // Direct address
    case AM_F: // EFLAGS register
    case AM_X: // Memory addressed by the DS:SI register pair
    case AM_Y: // Memory addressed by the ES:DI register pair
    case AM_IMPLICIT: // Parameter is implicit, occupies no space in
                       // instruction
      break;

    // There is a ModR/M byte but it does not necessarily need
    // to be decoded.
    case AM_C: // reg field of ModR/M selects a control register
    case AM_D: // reg field of ModR/M selects a debug register
    case AM_G: // reg field of ModR/M selects a general register
    case AM_P: // reg field of ModR/M selects an MMX register
    case AM_R: // mod field of ModR/M may refer only to a general register
    case AM_S: // reg field of ModR/M selects a segment register
    case AM_T: // reg field of ModR/M selects a test register
    case AM_V: // reg field of ModR/M selects a 128-bit XMM register
      have_modrm_ = true;
      break;

    // In these addressing modes, there is a ModR/M byte and it needs to be
    // decoded. No other (e.g. immediate) params than indicated in ModR/M.
    case AM_E: // Operand is either a general-purpose register or memory,
                 // specified by ModR/M byte
    case AM_M: // ModR/M byte will refer only to memory
    case AM_Q: // Operand is either an MMX register or memory (complex
                 // evaluation), specified by ModR/M byte
    case AM_W: // Operand is either a 128-bit XMM register or memory (complex
                 // eval), specified by ModR/M byte
      have_modrm_ = true;
      should_decode_modrm_ = true;
      break;

    // These addressing modes specify an immediate or an offset value
    // directly, so we need to look at the operand type to see how many
    // bytes.
    case AM_I: // Immediate data.
    case AM_J: // Jump to offset.
    case AM_O: // Operand is at offset.
      switch (flag_operand & OT_MASK) {
        case OT_B: // Byte regardless of operand-size attribute.
          operand_bytes_ += OS_BYTE;
          break;
        case OT_C: // Byte or word, depending on operand-size attribute.
          if (operand_is_32_bits_)
            operand_bytes_ += OS_WORD;
          else
            operand_bytes_ += OS_BYTE;
          break;
        case OT_D: // Doubleword, regardless of operand-size attribute.
          operand_bytes_ += OS_DOUBLE_WORD;
          break;
        case OT_DQ: // Double-quadword, regardless of operand-size attribute.
          operand_bytes_ += OS_DOUBLE_QUAD_WORD;
          break;
        case OT_P: // 32-bit or 48-bit pointer, depending on operand-size
                     // attribute.
          if (operand_is_32_bits_)
            operand_bytes_ += OS_48_BIT_POINTER;
          else
            operand_bytes_ += OS_32_BIT_POINTER;
          break;
        case OT_PS: // 128-bit packed single-precision floating-point data.
          operand_bytes_ += OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING;
          break;
        case OT_Q: // Quadword, regardless of operand-size attribute.
          operand_bytes_ += OS_QUAD_WORD;
          break;
        case OT_S: // 6-byte pseudo-descriptor.
          operand_bytes_ += OS_PSEUDO_DESCRIPTOR;
          break;
        case OT_SD: // Scalar Double-Precision Floating-Point Value
        case OT_PD: // Unaligned packed double-precision floating point value
          operand_bytes_ += OS_DOUBLE_PRECISION_FLOATING;
          break;
        case OT_SS:
          // Scalar element of a 128-bit packed single-precision
          // floating data.
          // We simply return enItUnknown since we don't have to support
          // floating point
          succeeded = false;
          break;
        case OT_V: // Word, doubleword or quadword, depending on operand-size
                   // attribute.
          if (operand_is_64_bits_ && flag_operand & AM_I &&
              flag_operand & IOS_64)
            operand_bytes_ += OS_QUAD_WORD;
          else if (operand_is_32_bits_)
            operand_bytes_ += OS_DOUBLE_WORD;
          else
            operand_bytes_ += OS_WORD;
          break;
        case OT_W: // Word, regardless of operand-size attribute.
          operand_bytes_ += OS_WORD;
          break;

        // Can safely ignore these.
        case OT_A: // Two one-word operands in memory or two double-word
                     // operands in memory
        case OT_PI: // Quadword MMX technology register (e.g. mm0)
        case OT_SI: // Doubleword integer register (e.g., eax)
          break;

        default:
          break;
      }
      break;

    default:
      break;
  }

  return succeeded;
}

bool MiniDisassembler::ProcessModrm(unsigned char* start_byte,
                                    unsigned int& size) {
  // If we don't need to decode, we just return the size of the ModR/M
  // byte (there is never a SIB byte in this case).
  if (!should_decode_modrm_) {
    size++;
    return true;
  }

  // We never care about the reg field, only the combination of the mod
  // and r/m fields, so let's start by packing those fields together into
  // 5 bits.
  unsigned char modrm = (*start_byte);
  unsigned char mod = modrm & 0xC0; // mask out top two bits to get mod field
  modrm = modrm & 0x07; // mask out bottom 3 bits to get r/m field
  mod = mod >> 3; // shift the mod field to the right place
  modrm = mod | modrm; // combine the r/m and mod fields as discussed
  mod = mod >> 3; // shift the mod field to bits 2..0

  // Invariant: modrm contains the mod field in bits 4..3 and the r/m field
  // in bits 2..0, and mod contains the mod field in bits 2..0

  const ModrmEntry* modrm_entry = 0;
  if (address_is_32_bits_)
    modrm_entry = &s_ia32_modrm_map_[modrm];
  else
    modrm_entry = &s_ia16_modrm_map_[modrm];

  // Invariant: modrm_entry points to information that we need to decode
  // the ModR/M byte.

  // Add to the count of operand bytes, if the ModR/M byte indicates
  // that some operands are encoded in the instruction.
  if (modrm_entry->is_encoded_in_instruction_)
    operand_bytes_ += modrm_entry->operand_size_;

  // Process the SIB byte if necessary, and return the count
  // of ModR/M and SIB bytes.
  if (modrm_entry->use_sib_byte_) {
    size++;
    return ProcessSib(start_byte + 1, mod, size);
  } else {
    size++;
    return true;
  }
}

bool MiniDisassembler::ProcessSib(unsigned char* start_byte,
                                  unsigned char mod,
                                  unsigned int& size) {
  // get the mod field from the 2..0 bits of the SIB byte
  unsigned char sib_base = (*start_byte) & 0x07;
  if (0x05 == sib_base) {
    switch (mod) {
    case 0x00: // mod == 00
    case 0x02: // mod == 10
      operand_bytes_ += OS_DOUBLE_WORD;
      break;
    case 0x01: // mod == 01
      operand_bytes_ += OS_BYTE;
      break;
    case 0x03: // mod == 11
      // According to the IA-32 docs, there does not seem to be a disp
      // value for this value of mod
    default:
      break;
    }
  }

  size++;
  return true;
}

};  // namespace sidestep
gperftools-gperftools-2.18/src/windows/mini_disassembler.h000066400000000000000000000177021513545575200241600ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 *
 * Definition of MiniDisassembler.
 */

#ifndef GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_
#define GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_

#include "config.h"
#include 
#include "mini_disassembler_types.h"

// compatibility shim
#include "base/logging.h"
#define SIDESTEP_ASSERT(cond)  RAW_DCHECK(cond, #cond)
#define SIDESTEP_LOG(msg)      RAW_VLOG(1, msg)

namespace sidestep {

// This small disassembler is very limited
// in its functionality, and in fact does only the bare minimum required by the
// preamble patching utility.  It may be useful for other purposes, however.
//
// The limitations include at least the following:
//  -# No support for coprocessor opcodes, MMX, etc.
//  -# No machine-readable identification of opcodes or decoding of
//     assembly parameters. The name of the opcode (as a string) is given,
//     however, to aid debugging.
//
// You may ask what this little disassembler actually does, then?  The answer is
// that it does the following, which is exactly what the patching utility needs:
//  -# Indicates if opcode is a jump (any kind) or a return (any kind)
//     because this is important for the patching utility to determine if
//     a function is too short or there are jumps too early in it for it
//     to be preamble patched.
//  -# The opcode length is always calculated, so that the patching utility
//     can figure out where the next instruction starts, and whether it
//     already has enough instructions to replace with the absolute jump
//     to the patching code.
//
// The usage is quite simple; just create a MiniDisassembler and use its
// Disassemble() method.
//
// If you would like to extend this disassembler, please refer to the
// IA-32 Intel® Architecture Software Developer's Manual Volume 2:
// Instruction Set Reference for information about operand decoding
// etc.
class PERFTOOLS_DLL_DECL MiniDisassembler {
 public:

  // Creates a new instance and sets defaults.
  //
  // @param operand_default_32_bits If true, the default operand size is
  // set to 32 bits, which is the default under Win32. Otherwise it is 16 bits.
  // @param address_default_32_bits If true, the default address size is
  // set to 32 bits, which is the default under Win32. Otherwise it is 16 bits.
  MiniDisassembler(bool operand_default_32_bits,
                   bool address_default_32_bits);

  // Equivalent to MiniDisassembler(true, true);
  MiniDisassembler();

  // Attempts to disassemble a single instruction starting from the
  // address in memory it is pointed to.
  //
  // @param start Address where disassembly should start.
  // @param instruction_bytes Variable that will be incremented by
  // the length in bytes of the instruction.
  // @return enItJump, enItReturn or enItGeneric on success.  enItUnknown
  // if unable to disassemble, enItUnused if this seems to be an unused
  // opcode. In the last two (error) cases, cbInstruction will be set
  // to 0xffffffff.
  //
  // @post This instance of the disassembler is ready to be used again,
  // with unchanged defaults from creation time.
  InstructionType Disassemble(unsigned char* start, unsigned int& instruction_bytes);

 private:

  // Makes the disassembler ready for reuse.
  void Initialize();

  // Sets the flags for address and operand sizes.
  // @return Number of prefix bytes.
  InstructionType ProcessPrefixes(unsigned char* start, unsigned int& size);

  // Sets the flag for whether we have ModR/M, and increments
  // operand_bytes_ if any are specifies by the opcode directly.
  // @return Number of opcode bytes.
  InstructionType ProcessOpcode(unsigned char* start,
                                unsigned int table,
                                unsigned int& size);

  // Checks the type of the supplied operand.  Increments
  // operand_bytes_ if it directly indicates an immediate etc.
  // operand.  Asserts have_modrm_ if the operand specifies
  // a ModR/M byte.
  bool ProcessOperand(int flag_operand);

  // Increments operand_bytes_ by size specified by ModR/M and
  // by SIB if present.
  // @return 0 in case of error, 1 if there is just a ModR/M byte,
  // 2 if there is a ModR/M byte and a SIB byte.
  bool ProcessModrm(unsigned char* start, unsigned int& size);

  // Processes the SIB byte that it is pointed to.
  // @param start Pointer to the SIB byte.
  // @param mod The mod field from the ModR/M byte.
  // @return 1 to indicate success (indicates 1 SIB byte)
  bool ProcessSib(unsigned char* start, unsigned char mod, unsigned int& size);

  // The instruction type we have decoded from the opcode.
  InstructionType instruction_type_;

  // Counts the number of bytes that is occupied by operands in
  // the current instruction (note: we don't care about how large
  // operands stored in registers etc. are).
  unsigned int operand_bytes_;

  // True iff there is a ModR/M byte in this instruction.
  bool have_modrm_;

  // True iff we need to decode the ModR/M byte (sometimes it just
  // points to a register, we can tell by the addressing mode).
  bool should_decode_modrm_;

  // Current operand size is 32 bits if true, 16 bits if false.
  bool operand_is_32_bits_;

  // Default operand size is 32 bits if true, 16 bits if false.
  bool operand_default_is_32_bits_;

  // Current address size is 32 bits if true, 16 bits if false.
  bool address_is_32_bits_;

  // Default address size is 32 bits if true, 16 bits if false.
  bool address_default_is_32_bits_;

  // Determines if 64 bit operands are supported (x64).
  bool operand_default_support_64_bits_;

  // Current operand size is 64 bits if true, 32 bits if false.
  bool operand_is_64_bits_;

  // Huge big opcode table based on the IA-32 manual, defined
  // in Ia32OpcodeMap.cc
  static const OpcodeTable s_ia32_opcode_map_[];

  // Somewhat smaller table to help with decoding ModR/M bytes
  // when 16-bit addressing mode is being used.  Defined in
  // Ia32ModrmMap.cc
  static const ModrmEntry s_ia16_modrm_map_[];

  // Somewhat smaller table to help with decoding ModR/M bytes
  // when 32-bit addressing mode is being used.  Defined in
  // Ia32ModrmMap.cc
  static const ModrmEntry s_ia32_modrm_map_[];

  // Indicators of whether we got certain prefixes that certain
  // silly Intel instructions depend on in nonstandard ways for
  // their behaviors.
  bool got_f2_prefix_, got_f3_prefix_, got_66_prefix_;
};

};  // namespace sidestep

#endif  // GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_
gperftools-gperftools-2.18/src/windows/mini_disassembler_types.h000066400000000000000000000205001513545575200253720ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 *
 * Several simple types used by the disassembler and some of the patching
 * mechanisms.
 */

#ifndef GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_
#define GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_

namespace sidestep {

// Categories of instructions that we care about
enum InstructionType {
  // This opcode is not used
  IT_UNUSED,
  // This disassembler does not recognize this opcode (error)
  IT_UNKNOWN,
  // This is not an instruction but a reference to another table
  IT_REFERENCE,
  // This byte is a prefix byte that we can ignore
  IT_PREFIX,
  // This is a prefix byte that switches to the nondefault address size
  IT_PREFIX_ADDRESS,
  // This is a prefix byte that switches to the nondefault operand size
  IT_PREFIX_OPERAND,
  // A jump or call instruction
  IT_JUMP,
  // A return instruction
  IT_RETURN,
  // Any other type of instruction (in this case we don't care what it is)
  IT_GENERIC,
};

// Lists IA-32 operand sizes in multiples of 8 bits
enum OperandSize {
  OS_ZERO = 0,
  OS_BYTE = 1,
  OS_WORD = 2,
  OS_DOUBLE_WORD = 4,
  OS_QUAD_WORD = 8,
  OS_DOUBLE_QUAD_WORD = 16,
  OS_32_BIT_POINTER = 32/8,
  OS_48_BIT_POINTER = 48/8,
  OS_SINGLE_PRECISION_FLOATING = 32/8,
  OS_DOUBLE_PRECISION_FLOATING = 64/8,
  OS_DOUBLE_EXTENDED_PRECISION_FLOATING = 80/8,
  OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING = 128/8,
  OS_PSEUDO_DESCRIPTOR = 6
};

// Operand addressing methods from the IA-32 manual.  The enAmMask value
// is a mask for the rest.  The other enumeration values are named for the
// names given to the addressing methods in the manual, e.g. enAm_D is for
// the D addressing method.
//
// The reason we use a full 4 bytes and a mask, is that we need to combine
// these flags with the enOperandType to store the details
// on the operand in a single integer.
enum AddressingMethod {
  AM_NOT_USED = 0,        // This operand is not used for this instruction
  AM_MASK = 0x00FF0000,  // Mask for the rest of the values in this enumeration
  AM_A = 0x00010000,    // A addressing type
  AM_C = 0x00020000,    // C addressing type
  AM_D = 0x00030000,    // D addressing type
  AM_E = 0x00040000,    // E addressing type
  AM_F = 0x00050000,    // F addressing type
  AM_G = 0x00060000,    // G addressing type
  AM_I = 0x00070000,    // I addressing type
  AM_J = 0x00080000,    // J addressing type
  AM_M = 0x00090000,    // M addressing type
  AM_O = 0x000A0000,    // O addressing type
  AM_P = 0x000B0000,    // P addressing type
  AM_Q = 0x000C0000,    // Q addressing type
  AM_R = 0x000D0000,    // R addressing type
  AM_S = 0x000E0000,    // S addressing type
  AM_T = 0x000F0000,    // T addressing type
  AM_V = 0x00100000,    // V addressing type
  AM_W = 0x00110000,    // W addressing type
  AM_X = 0x00120000,    // X addressing type
  AM_Y = 0x00130000,    // Y addressing type
  AM_REGISTER = 0x00140000,  // Specific register is always used as this op
  AM_IMPLICIT = 0x00150000,  // An implicit, fixed value is used
};

// Operand types from the IA-32 manual. The enOtMask value is
// a mask for the rest. The rest of the values are named for the
// names given to these operand types in the manual, e.g. enOt_ps
// is for the ps operand type in the manual.
//
// The reason we use a full 4 bytes and a mask, is that we need
// to combine these flags with the enAddressingMethod to store the details
// on the operand in a single integer.
enum OperandType : unsigned {
  OT_MASK = 0xFF000000,
  OT_A = 0x01000000,
  OT_B = 0x02000000,
  OT_C = 0x03000000,
  OT_D = 0x04000000,
  OT_DQ = 0x05000000,
  OT_P = 0x06000000,
  OT_PI = 0x07000000,
  OT_PS = 0x08000000,  // actually unsupported for (we don't know its size)
  OT_Q = 0x09000000,
  OT_S = 0x0A000000,
  OT_SS = 0x0B000000,
  OT_SI = 0x0C000000,
  OT_V = 0x0D000000,
  OT_W = 0x0E000000,
  OT_SD = 0x0F000000,  // scalar double-precision floating-point value
  OT_PD = 0x10000000,  // double-precision floating point
  // dummy "operand type" for address mode M - which doesn't specify
  // operand type
  OT_ADDRESS_MODE_M = 0x80000000
};

// Flag that indicates if an immediate operand is 64-bits.
//
// The Intel 64 and IA-32 Architecture Software Developer's Manual currently
// defines MOV as the only instruction supporting a 64-bit immediate operand.
enum ImmediateOperandSize {
  IOS_MASK = 0x0000F000,
  IOS_DEFAULT = 0x0,
  IOS_64 = 0x00001000
};

// Everything that's in an Opcode (see below) except the three
// alternative opcode structs for different prefixes.
struct SpecificOpcode {
  // Index to continuation table, or 0 if this is the last
  // byte in the opcode.
  int table_index_;

  // The opcode type
  InstructionType type_;

  // Description of the type of the dest, src and aux operands,
  // put together from enOperandType, enAddressingMethod and
  // enImmediateOperandSize flags.
  int flag_dest_;
  int flag_source_;
  int flag_aux_;

  // We indicate the mnemonic for debugging purposes
  const char* mnemonic_;
};

// The information we keep in our tables about each of the different
// valid instructions recognized by the IA-32 architecture.
struct Opcode {
  // Index to continuation table, or 0 if this is the last
  // byte in the opcode.
  int table_index_;

  // The opcode type
  InstructionType type_;

  // Description of the type of the dest, src and aux operands,
  // put together from an enOperandType flag and an enAddressingMethod
  // flag.
  unsigned flag_dest_;
  unsigned flag_source_;
  unsigned flag_aux_;

  // We indicate the mnemonic for debugging purposes
  const char* mnemonic_;

  // Alternative opcode info if certain prefixes are specified.
  // In most cases, all of these are zeroed-out.  Only used if
  // bPrefixDependent is true.
  bool is_prefix_dependent_;
  SpecificOpcode opcode_if_f2_prefix_;
  SpecificOpcode opcode_if_f3_prefix_;
  SpecificOpcode opcode_if_66_prefix_;
};

// Information about each table entry.
struct OpcodeTable {
  // Table of instruction entries
  const Opcode* table_;
  // How many bytes left to shift ModR/M byte before applying mask
  unsigned char shift_;
  // Mask to apply to byte being looked at before comparing to table
  unsigned char mask_;
  // Minimum/maximum indexes in table.
  unsigned char min_lim_;
  unsigned char max_lim_;
};

// Information about each entry in table used to decode ModR/M byte.
struct ModrmEntry {
  // Is the operand encoded as bytes in the instruction (rather than
  // if it's e.g. a register in which case it's just encoded in the
  // ModR/M byte)
  bool is_encoded_in_instruction_;

  // Is there a SIB byte?  In this case we always need to decode it.
  bool use_sib_byte_;

  // What is the size of the operand (only important if it's encoded
  // in the instruction)?
  OperandSize operand_size_;
};

};  // namespace sidestep

#endif  // GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_
gperftools-gperftools-2.18/src/windows/override_functions.cc000066400000000000000000000120421513545575200245240ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Mike Belshe
//
// To link tcmalloc into a EXE or DLL statically without using the patching
// facility, we can take a stock libcmt and remove all the allocator functions.
// When we relink the EXE/DLL with the modified libcmt and tcmalloc, a few
// functions are missing.  This file contains the additional overrides which
// are required in the VS2005 libcmt in order to link the modified libcmt.
//
// See also
// http://groups.google.com/group/google-perftools/browse_thread/thread/41cd3710af85e57b

#include 

#ifndef _WIN32
# error You should only be including this file in a windows environment!
#endif

#ifndef WIN32_OVERRIDE_ALLOCATORS
# error This file is intended for use when overriding allocators
#endif

#include "tcmalloc.cc"

extern "C" {

void* _malloc_base(size_t size) {
  return malloc(size);
}

void _free_base(void* p) {
  free(p);
}

void* _calloc_base(size_t n, size_t size) {
  return calloc(n, size);
}

void* _recalloc(void* old_ptr, size_t n, size_t size) {
  // Ensure that (n * size) does not overflow
  if (!(n == 0 || (std::numeric_limits::max)() / n >= size)) {
    errno = ENOMEM;
    return nullptr;
  }

  const size_t old_size = tc_malloc_size(old_ptr);
  const size_t new_size = n * size;

  void* new_ptr = realloc(old_ptr, new_size);

  // If the reallocation succeeded and the new block is larger, zero-fill the
  // new bytes:
  if (new_ptr != nullptr && new_size > old_size) {
    memset(static_cast(new_ptr) + old_size, 0, tc_nallocx(new_size, 0) - old_size);
  }

  return new_ptr;
}

void* _recalloc_base(void* old_ptr, size_t n, size_t size) {
  return _recalloc(old_ptr, n, size);
}

void* _calloc_impl(size_t n, size_t size) {
  return calloc(n, size);
}

size_t _msize(void* p) {
  return MallocExtension::instance()->GetAllocatedSize(p);
}

size_t _msize_base(void* p) noexcept {
  return MallocExtension::instance()->GetAllocatedSize(p);
}

HANDLE __acrt_heap = nullptr;

bool __acrt_initialize_heap() {
  new TCMallocGuard();
  return true;
}

bool __acrt_uninitialize_heap(bool) {
  return true;
}

intptr_t _get_heap_handle() {
  return 0;
}

HANDLE __acrt_getheap() {
  return __acrt_heap;
}

// The CRT heap initialization stub.
int _heap_init() {
  // We intentionally leak this object.  It lasts for the process
  // lifetime.  Trying to teardown at _heap_term() is so late that
  // you can't do anything useful anyway.
  new TCMallocGuard();
  return 1;
}

// The CRT heap cleanup stub.
void _heap_term() {
}

// We set this to 1 because part of the CRT uses a check of _crtheap != 0
// to test whether the CRT has been initialized.  Once we've ripped out
// the allocators from libcmt, we need to provide this definition so that
// the rest of the CRT is still usable.
void* _crtheap = reinterpret_cast(1);

int _set_new_mode(int flag) {
  return tc_set_new_mode(flag);
}

int _query_new_mode() {
  return tc_query_new_mode();
}

}  // extern "C"

#ifndef NDEBUG
#undef malloc
#undef free
#undef calloc
int _CrtDbgReport(int, const char*, int, const char*, const char*, ...) {
  return 0;
}

int _CrtDbgReportW(int, const wchar_t*, int, const wchar_t*, const wchar_t*, ...) {
  return 0;
}

int _CrtSetReportMode(int, int) {
  return 0;
}

extern "C" void* _malloc_dbg(size_t size, int , const char*, int) {
  return malloc(size);
}

extern "C" void _free_dbg(void* ptr, int) {
  free(ptr);
}

extern "C" void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
  return calloc(n, size);
}
#endif  // NDEBUG
gperftools-gperftools-2.18/src/windows/patch_functions.cc000066400000000000000000001271361513545575200240170ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Craig Silverstein
//
// The main purpose of this file is to patch the libc allocation
// routines (malloc and friends, but also _msize and other
// windows-specific libc-style routines).  However, we also patch
// windows routines to do accounting.  We do better at the former than
// the latter.  Here are some comments from Paul Pluzhnikov about what
// it might take to do a really good job patching windows routines to
// keep track of memory usage:
//
// "You should intercept at least the following:
//     HeapCreate HeapDestroy HeapAlloc HeapReAlloc HeapFree
//     RtlCreateHeap RtlDestroyHeap RtlAllocateHeap RtlFreeHeap
//     malloc calloc realloc free
//     malloc_dbg calloc_dbg realloc_dbg free_dbg
// Some of these call the other ones (but not always), sometimes
// recursively (i.e. HeapCreate may call HeapAlloc on a different
// heap, IIRC)."
//
// Since Paul didn't mention VirtualAllocEx, he may not have even been
// considering all the mmap-like functions that windows has (or he may
// just be ignoring it because he's seen we already patch it).  Of the
// above, we do not patch the *_dbg functions, and of the windows
// functions, we only patch HeapAlloc and HeapFree.
//
// The *_dbg functions come into play with /MDd, /MTd, and /MLd,
// probably.  It may be ok to just turn off tcmalloc in those cases --
// if the user wants the windows debug malloc, they probably don't
// want tcmalloc!  We should also test with all of /MD, /MT, and /ML,
// which we're not currently doing.

// TODO(csilvers): try to do better here?  Paul does conclude:
//                 "Keeping track of all of this was a nightmare."

#ifndef _WIN32
# error You should only be including windows/patch_functions.cc in a windows environment!
#endif

#include 

#ifdef WIN32_OVERRIDE_ALLOCATORS
#error This file is intended for patching allocators - use override_functions.cc instead.
#endif

// We use psapi.  Non-MSVC systems will have to link this in themselves.
#ifdef _MSC_VER
#pragma comment(lib, "Psapi.lib")
#endif

// Make sure we always use the 'old' names of the psapi functions.
#ifndef PSAPI_VERSION
#define PSAPI_VERSION 1
#endif

#include 
#include 
#include        // for _msize and _expand
#include         // for EnumProcessModules, GetModuleInformation, etc.
#include 
#include 
#include 
#include 
#include "base/spinlock.h"
#include "getenv_safe.h" // for TCMallocGetenvSafe
#include "gperftools/malloc_hook.h"
#include "malloc_hook-inl.h"
#include "preamble_patcher.h"

// The maximum number of modules we allow to be in one executable
const int kMaxModules = 8182;

// These are hard-coded, unfortunately. :-( They are also probably
// compiler specific.  See get_mangled_names.cc, in this directory,
// for instructions on how to update these names for your compiler.
#ifdef _WIN64
const char kMangledNew[] = "??2@YAPEAX_K@Z";
const char kMangledNewArray[] = "??_U@YAPEAX_K@Z";
const char kMangledDelete[] = "??3@YAXPEAX@Z";
const char kMangledDeleteArray[] = "??_V@YAXPEAX@Z";
const char kMangledNewNothrow[] = "??2@YAPEAX_KAEBUnothrow_t@std@@@Z";
const char kMangledNewArrayNothrow[] = "??_U@YAPEAX_KAEBUnothrow_t@std@@@Z";
const char kMangledDeleteNothrow[] = "??3@YAXPEAXAEBUnothrow_t@std@@@Z";
const char kMangledDeleteArrayNothrow[] = "??_V@YAXPEAXAEBUnothrow_t@std@@@Z";
#else
const char kMangledNew[] = "??2@YAPAXI@Z";
const char kMangledNewArray[] = "??_U@YAPAXI@Z";
const char kMangledDelete[] = "??3@YAXPAX@Z";
const char kMangledDeleteArray[] = "??_V@YAXPAX@Z";
const char kMangledNewNothrow[] = "??2@YAPAXIABUnothrow_t@std@@@Z";
const char kMangledNewArrayNothrow[] = "??_U@YAPAXIABUnothrow_t@std@@@Z";
const char kMangledDeleteNothrow[] = "??3@YAXPAXABUnothrow_t@std@@@Z";
const char kMangledDeleteArrayNothrow[] = "??_V@YAXPAXABUnothrow_t@std@@@Z";
#endif

// This is an unused but exported symbol that we can use to tell the
// MSVC linker to bring in libtcmalloc, via the /INCLUDE linker flag.
// Without this, the linker will likely decide that libtcmalloc.dll
// doesn't add anything to the executable (since it does all its work
// through patching, which the linker can't see), and ignore it
// entirely.  (The name 'tcmalloc' is already reserved for a
// namespace.  I'd rather export a variable named "_tcmalloc", but I
// couldn't figure out how to get that to work.  This function exports
// the symbol "__tcmalloc".)
extern "C" PERFTOOLS_DLL_DECL void _tcmalloc();
void _tcmalloc() { }

// This is the version needed for windows x64, which has a different
// decoration scheme which doesn't auto-add a leading underscore.
extern "C" PERFTOOLS_DLL_DECL void __tcmalloc();
void __tcmalloc() { }

namespace {    // most everything here is in an unnamed namespace

typedef void (*GenericFnPtr)();

using sidestep::PreamblePatcher;

struct ModuleEntryCopy;   // defined below

// These functions are how we override the memory allocation
// functions, just like tcmalloc.cc and malloc_hook.cc do.

// This is information about the routines we're patching, for a given
// module that implements libc memory routines.  A single executable
// can have several libc implementations running about (in different
// .dll's), and we need to patch/unpatch them all.  This defines
// everything except the new functions we're patching in, which
// are defined in LibcFunctions, below.
class LibcInfo {
 public:
  LibcInfo() {
    memset(this, 0, sizeof(*this));  // easiest way to initialize the array
  }

  bool patched() const { return is_valid(); }
  void set_is_valid(bool b) { is_valid_ = b; }
  // According to http://msdn.microsoft.com/en-us/library/ms684229(VS.85).aspx:
  // "The load address of a module (lpBaseOfDll) is the same as the HMODULE
  // value."
  HMODULE hmodule() const {
    return reinterpret_cast(const_cast(module_base_address_));
  }

  // Populates all the windows_fn_[] vars based on our module info.
  // Returns false if windows_fn_ is all nullptr's, because there's
  // nothing to patch.  Also populates the rest of the module_entry
  // info, such as the module's name.
  bool PopulateWindowsFn(const ModuleEntryCopy& module_entry);

 protected:
  void CopyFrom(const LibcInfo& that) {
    if (this == &that)
      return;
    this->is_valid_ = that.is_valid_;
    memcpy(this->windows_fn_, that.windows_fn_, sizeof(windows_fn_));
    this->module_base_address_ = that.module_base_address_;
    this->module_base_size_ = that.module_base_size_;
  }

  enum {
    kMalloc, kFree, kRealloc, kCalloc,
    kNew, kNewArray, kDelete, kDeleteArray,
    kNewNothrow, kNewArrayNothrow, kDeleteNothrow, kDeleteArrayNothrow,
    // These are windows-only functions from malloc.h
    k_Msize, k_Expand,
    // A MS CRT "internal" function, implemented using _calloc_impl
    k_CallocCrt,
    // Underlying deallocation functions called by CRT internal functions or operator delete
    kFreeBase, kFreeDbg,
    kNumFunctions
  };

  // I'd like to put these together in a struct (perhaps in the
  // subclass, so we can put in perftools_fn_ as well), but vc8 seems
  // to have a bug where it doesn't initialize the struct properly if
  // we try to take the address of a function that's not yet loaded
  // from a dll, as is the common case for static_fn_.  So we need
  // each to be in its own array. :-(
  static const char* const function_name_[kNumFunctions];

  // This function is only used when statically linking the binary.
  // In that case, loading malloc/etc from the dll (via
  // PatchOneModule) won't work, since there are no dlls.  Instead,
  // you just want to be taking the address of malloc/etc directly.
  // In the common, non-static-link case, these pointers will all be
  // nullptr, since this initializer runs before msvcrt.dll is loaded.
  static const GenericFnPtr static_fn_[kNumFunctions];

  // This is the address of the function we are going to patch
  // (malloc, etc).  Other info about the function is in the
  // patch-specific subclasses, below.
  GenericFnPtr windows_fn_[kNumFunctions];

  // This is set to true when this structure is initialized (because
  // we're patching a new library) and set to false when it's
  // uninitialized (because we've freed that library).
  bool is_valid_;

  const void *module_base_address_;
  size_t module_base_size_;

 public:
  // These shouldn't have to be public, since only subclasses of
  // LibcInfo need it, but they do.  Maybe something to do with
  // templates.  Shrug.  I hide them down here so users won't see
  // them. :-)  (OK, I also need to define ctrgProcAddress late.)
  bool is_valid() const { return is_valid_; }
  GenericFnPtr windows_fn(int ifunction) const {
    return windows_fn_[ifunction];
  }
  // These three are needed by ModuleEntryCopy.
  static const int ctrgProcAddress = kNumFunctions;
  static GenericFnPtr static_fn(int ifunction) {
    return static_fn_[ifunction];
  }
  static const char* const function_name(int ifunction) {
    return function_name_[ifunction];
  }
};

// Template trickiness: logically, a LibcInfo would include
// Windows_malloc_, origstub_malloc_, and Perftools_malloc_: for a
// given module, these three go together.  And in fact,
// Perftools_malloc_ may need to call origstub_malloc_, which means we
// either need to change Perftools_malloc_ to take origstub_malloc_ as
// an argument -- unfortunately impossible since it needs to keep the
// same API as normal malloc -- or we need to write a different
// version of Perftools_malloc_ for each LibcInfo instance we create.
// We choose the second route, and use templates to implement it (we
// could have also used macros).  So to get multiple versions
// of the struct, we say "struct<1> var1; struct<2> var2;".  The price
// we pay is some code duplication, and more annoying, each instance
// of this var is a separate type.
template class LibcInfoWithPatchFunctions : public LibcInfo {
 public:
  // me_info should have had PopulateWindowsFn() called on it, so the
  // module_* vars and windows_fn_ are set up.
  bool Patch(const LibcInfo& me_info);
  void Unpatch();

 private:
  // This holds the original function contents after we patch the function.
  // This has to be defined static in the subclass, because the perftools_fns
  // reference origstub_fn_.
  static GenericFnPtr origstub_fn_[kNumFunctions];

  // This is the function we want to patch in
  static const GenericFnPtr perftools_fn_[kNumFunctions];

  static void* Perftools_malloc(size_t size) __THROW;
  static void Perftools_free(void* ptr) __THROW;
  static void Perftools_free_base(void* ptr) __THROW;
  static void Perftools_free_dbg(void* ptr, int block_use) __THROW;
  static void* Perftools_realloc(void* ptr, size_t size) __THROW;
  static void* Perftools_calloc(size_t nmemb, size_t size) __THROW;
  static void* Perftools_new(size_t size);
  static void* Perftools_newarray(size_t size);
  static void Perftools_delete(void *ptr);
  static void Perftools_deletearray(void *ptr);
  static void* Perftools_new_nothrow(size_t size,
                                     const std::nothrow_t&) __THROW;
  static void* Perftools_newarray_nothrow(size_t size,
                                          const std::nothrow_t&) __THROW;
  static void Perftools_delete_nothrow(void *ptr,
                                       const std::nothrow_t&) __THROW;
  static void Perftools_deletearray_nothrow(void *ptr,
                                            const std::nothrow_t&) __THROW;
  static size_t Perftools__msize(void *ptr) __THROW;
  static void* Perftools__expand(void *ptr, size_t size) __THROW;
  // malloc.h also defines these functions:
  //   _aligned_malloc, _aligned_free,
  //   _recalloc, _aligned_offset_malloc, _aligned_realloc, _aligned_recalloc
  //   _aligned_offset_realloc, _aligned_offset_recalloc, _malloca, _freea
  // But they seem pretty obscure, and I'm fine not overriding them for now.
  // It may be they all call into malloc/free anyway.
};

// This is a subset of MODDULEENTRY32, that we need for patching.
struct ModuleEntryCopy {
  LPVOID  modBaseAddr;     // the same as hmodule
  DWORD   modBaseSize;
  // This is not part of MODDULEENTRY32, but is needed to avoid making
  // windows syscalls while we're holding patch_all_modules_lock (see
  // lock-inversion comments at patch_all_modules_lock definition, below).
  GenericFnPtr rgProcAddresses[LibcInfo::ctrgProcAddress];

  ModuleEntryCopy() {
    modBaseAddr = nullptr;
    modBaseSize = 0;
    for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++)
      rgProcAddresses[i] = LibcInfo::static_fn(i);
  }
  ModuleEntryCopy(const MODULEINFO& mi) {
    this->modBaseAddr = mi.lpBaseOfDll;
    this->modBaseSize = mi.SizeOfImage;
    LPVOID modEndAddr = (char*)mi.lpBaseOfDll + mi.SizeOfImage;
    for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) {
      FARPROC target = ::GetProcAddress(
          reinterpret_cast(mi.lpBaseOfDll),
          LibcInfo::function_name(i));
      void* target_addr = reinterpret_cast(target);
      // Sometimes a DLL forwards a function to a function in another
      // DLL.  We don't want to patch those forwarded functions --
      // they'll get patched when the other DLL is processed.
      if (modBaseAddr <= target_addr && target_addr < modEndAddr)
        rgProcAddresses[i] = (GenericFnPtr)target;
      else
        rgProcAddresses[i] = (GenericFnPtr)nullptr;
    }
  }
};

// This class is easier because there's only one of them.
class WindowsInfo {
 public:
  void Patch();
  void Unpatch();

 private:
  // TODO(csilvers): should we be patching GlobalAlloc/LocalAlloc instead,
  //                 for pre-XP systems?
  enum {
    kHeapAlloc, kHeapFree, kLoadLibraryExW, kFreeLibrary,
    kNumFunctions
  };

  struct FunctionInfo {
    const char* const name;          // name of fn in a module (eg "malloc")
    GenericFnPtr windows_fn;         // the fn whose name we call (&malloc)
    GenericFnPtr origstub_fn;        // original fn contents after we patch
    const GenericFnPtr perftools_fn; // fn we want to patch in
  };

  static FunctionInfo function_info_[kNumFunctions];

  // A Windows-API equivalent of malloc and free
  static LPVOID WINAPI Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags,
                                           DWORD_PTR dwBytes);
  static BOOL WINAPI Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags,
                                        LPVOID lpMem);
  // We don't need the other 3 variants because they all call this one. */
  static HMODULE WINAPI Perftools_LoadLibraryExW(LPCWSTR lpFileName,
                                                 HANDLE hFile,
                                                 DWORD dwFlags);
  static BOOL WINAPI Perftools_FreeLibrary(HMODULE hLibModule);
};

// If you run out, just add a few more to the array.  You'll also need
// to update the switch statement in PatchOneModule(), and the list in
// UnpatchWindowsFunctions().
// main_executable and main_executable_windows are two windows into
// the same executable.  One is responsible for patching the libc
// routines that live in the main executable (if any) to use tcmalloc;
// the other is responsible for patching the windows routines like
// HeapAlloc/etc to use tcmalloc.
static LibcInfoWithPatchFunctions<0> main_executable;
static LibcInfoWithPatchFunctions<1> libc1;
static LibcInfoWithPatchFunctions<2> libc2;
static LibcInfoWithPatchFunctions<3> libc3;
static LibcInfoWithPatchFunctions<4> libc4;
static LibcInfoWithPatchFunctions<5> libc5;
static LibcInfoWithPatchFunctions<6> libc6;
static LibcInfoWithPatchFunctions<7> libc7;
static LibcInfoWithPatchFunctions<8> libc8;
static LibcInfo* g_module_libcs[] = {
  &libc1, &libc2, &libc3, &libc4, &libc5, &libc6, &libc7, &libc8
};
static WindowsInfo main_executable_windows;

const char* const LibcInfo::function_name_[] = {
  "malloc", "free", "realloc", "calloc",
  kMangledNew, kMangledNewArray, kMangledDelete, kMangledDeleteArray,
  // Ideally we should patch the nothrow versions of new/delete, but
  // at least in msvcrt, nothrow-new machine-code is of a type we
  // can't patch.  Since these are relatively rare, I'm hoping it's ok
  // not to patch them.  (nullptr name turns off patching.)
  nullptr,  // kMangledNewNothrow,
  nullptr,  // kMangledNewArrayNothrow,
  nullptr,  // kMangledDeleteNothrow,
  nullptr,  // kMangledDeleteArrayNothrow,
  "_msize", "_expand", "_calloc_crt", "_free_base", "_free_dbg"
};

// For mingw, I can't patch the new/delete here, because the
// instructions are too small to patch.  Luckily, they're so small
// because all they do is call into malloc/free, so they still end up
// calling tcmalloc routines, and we don't actually lose anything
// (except maybe some stacktrace goodness) by not patching.
const GenericFnPtr LibcInfo::static_fn_[] = {
  (GenericFnPtr)&::malloc,
  (GenericFnPtr)&::free,
  (GenericFnPtr)&::realloc,
  (GenericFnPtr)&::calloc,
#ifdef __MINGW32__
  nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
#else
  (GenericFnPtr)(void*(*)(size_t))&::operator new,
  (GenericFnPtr)(void*(*)(size_t))&::operator new[],
  (GenericFnPtr)(void(*)(void*))&::operator delete,
  (GenericFnPtr)(void(*)(void*))&::operator delete[],
  (GenericFnPtr)
  (void*(*)(size_t, struct std::nothrow_t const &))&::operator new,
  (GenericFnPtr)
  (void*(*)(size_t, struct std::nothrow_t const &))&::operator new[],
  (GenericFnPtr)
  (void(*)(void*, struct std::nothrow_t const &))&::operator delete,
  (GenericFnPtr)
  (void(*)(void*, struct std::nothrow_t const &))&::operator delete[],
#endif
  (GenericFnPtr)&::_msize,
  (GenericFnPtr)&::_expand,
  (GenericFnPtr)&::calloc,
  (GenericFnPtr)&::free,
  (GenericFnPtr)&::free
};

template GenericFnPtr LibcInfoWithPatchFunctions::origstub_fn_[] = {
  // This will get filled in at run-time, as patching is done.
};

// _expand() is like realloc but doesn't move the
// pointer.  We punt, which will cause callers to fall back on realloc.
static void* empty__expand(void*, size_t) __THROW {
  return nullptr;
}

template
const GenericFnPtr LibcInfoWithPatchFunctions::perftools_fn_[] = {
  (GenericFnPtr)&Perftools_malloc,
  (GenericFnPtr)&Perftools_free,
  (GenericFnPtr)&Perftools_realloc,
  (GenericFnPtr)&Perftools_calloc,
  (GenericFnPtr)&Perftools_new,
  (GenericFnPtr)&Perftools_newarray,
  (GenericFnPtr)&Perftools_delete,
  (GenericFnPtr)&Perftools_deletearray,
  (GenericFnPtr)&Perftools_new_nothrow,
  (GenericFnPtr)&Perftools_newarray_nothrow,
  (GenericFnPtr)&Perftools_delete_nothrow,
  (GenericFnPtr)&Perftools_deletearray_nothrow,
  (GenericFnPtr)&Perftools__msize,
  (GenericFnPtr)&empty__expand,
  (GenericFnPtr)&Perftools_calloc,
  (GenericFnPtr)&Perftools_free_base,
  (GenericFnPtr)&Perftools_free_dbg
};

/*static*/ WindowsInfo::FunctionInfo WindowsInfo::function_info_[] = {
  { "HeapAlloc", nullptr, nullptr, (GenericFnPtr)&Perftools_HeapAlloc },
  { "HeapFree", nullptr, nullptr, (GenericFnPtr)&Perftools_HeapFree },
  { "LoadLibraryExW", nullptr, nullptr, (GenericFnPtr)&Perftools_LoadLibraryExW },
  { "FreeLibrary", nullptr, nullptr, (GenericFnPtr)&Perftools_FreeLibrary },
};

bool LibcInfo::PopulateWindowsFn(const ModuleEntryCopy& module_entry) {
  // First, store the location of the function to patch before
  // patching it.  If none of these functions are found in the module,
  // then this module has no libc in it, and we just return false.
  for (int i = 0; i < kNumFunctions; i++) {
    if (!function_name_[i])     // we can turn off patching by unsetting name
      continue;
    // The ::GetProcAddress calls were done in the ModuleEntryCopy
    // constructor, so we don't have to make any windows calls here.
    const GenericFnPtr fn = module_entry.rgProcAddresses[i];
    if (fn) {
      windows_fn_[i] = PreamblePatcher::ResolveTarget(fn);
    }
  }

  // Some modules use the same function pointer for new and new[].  If
  // we find that, set one of the pointers to nullptr so we don't double-
  // patch.  Same may happen with new and nothrow-new, or even new[]
  // and nothrow-new.  It's easiest just to check each fn-ptr against
  // every other.
  for (int i = 0; i < kNumFunctions; i++) {
    for (int j = i+1; j < kNumFunctions; j++) {
      if (windows_fn_[i] == windows_fn_[j]) {
        // We nullptr the later one (j), so as to minimize the chances we
        // nullptr kFree and kRealloc.  See comments below.  This is fragile!
        windows_fn_[j] = nullptr;
      }
    }
  }

  // There's always a chance that our module uses the same function
  // as another module that we've already loaded.  In that case, we
  // need to set our windows_fn to nullptr, to avoid double-patching.
  for (int ifn = 0; ifn < kNumFunctions; ifn++) {
    for (int imod = 0;
         imod < sizeof(g_module_libcs)/sizeof(*g_module_libcs);  imod++) {
      if (g_module_libcs[imod]->is_valid() &&
          this->windows_fn(ifn) == g_module_libcs[imod]->windows_fn(ifn)) {
        windows_fn_[ifn] = nullptr;
      }
    }
  }

  bool found_non_null = false;
  for (int i = 0; i < kNumFunctions; i++) {
    if (windows_fn_[i])
      found_non_null = true;
  }
  if (!found_non_null)
    return false;

  // It's important we didn't nullptr out windows_fn_[kFree] or [kRealloc].
  // The reason is, if those are nullptr-ed out, we'll never patch them
  // and thus never get an origstub_fn_ value for them, and when we
  // try to call origstub_fn_[kFree/kRealloc] in Perftools_free and
  // Perftools_realloc, below, it will fail.  We could work around
  // that by adding a pointer from one patch-unit to the other, but we
  // haven't needed to yet.
  CHECK(windows_fn_[kFree]);
  CHECK(windows_fn_[kRealloc]);

  // OK, we successfully populated.  Let's store our member information.
  module_base_address_ = module_entry.modBaseAddr;
  module_base_size_ = module_entry.modBaseSize;
  return true;
}

template
bool LibcInfoWithPatchFunctions::Patch(const LibcInfo& me_info) {
  CopyFrom(me_info);   // copies the module_entry and the windows_fn_ array
  for (int i = 0; i < kNumFunctions; i++) {
    if (windows_fn_[i] && windows_fn_[i] != perftools_fn_[i]) {
      // if origstub_fn_ is not nullptr, it's left around from a previous
      // patch.  We need to set it to nullptr for the new Patch call.
      //
      // Note that origstub_fn_ was logically freed by
      // PreamblePatcher::Unpatch, so we don't have to do anything
      // about it.
      origstub_fn_[i] = nullptr;   // Patch() will fill this in
      CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
               PreamblePatcher::Patch(windows_fn_[i], perftools_fn_[i],
                                      &origstub_fn_[i]));
    }
  }
  set_is_valid(true);
  return true;
}

template
void LibcInfoWithPatchFunctions::Unpatch() {
  // We have to cast our GenericFnPtrs to void* for unpatch.  This is
  // contra the C++ spec; we use C-style casts to empahsize that.
  for (int i = 0; i < kNumFunctions; i++) {
    if (windows_fn_[i])
      CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
               PreamblePatcher::Unpatch((void*)windows_fn_[i],
                                        (void*)perftools_fn_[i],
                                        (void*)origstub_fn_[i]));
  }
  set_is_valid(false);
}

void WindowsInfo::Patch() {
  HMODULE hkernel32 = ::GetModuleHandleA("kernel32");
  CHECK_NE(hkernel32, nullptr);

  // Unlike for libc, we know these exist in our module, so we can get
  // and patch at the same time.
  for (int i = 0; i < kNumFunctions; i++) {
    function_info_[i].windows_fn = (GenericFnPtr)
        ::GetProcAddress(hkernel32, function_info_[i].name);
    // If origstub_fn is not nullptr, it's left around from a previous
    // patch.  We need to set it to nullptr for the new Patch call.
    // Since we've patched Unpatch() not to delete origstub_fn_ (it
    // causes problems in some contexts, though obviously not this
    // one), we should delete it now, before setting it to nullptr.
    // NOTE: casting from a function to a pointer is contra the C++
    //       spec.  It's not safe on IA64, but is on i386.  We use
    //       a C-style cast here to emphasize this is not legal C++.
    delete[] (char*)(function_info_[i].origstub_fn);
    function_info_[i].origstub_fn = nullptr;  // Patch() will fill this in
    CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
             PreamblePatcher::Patch(function_info_[i].windows_fn,
                                    function_info_[i].perftools_fn,
                                    &function_info_[i].origstub_fn));
  }
}

void WindowsInfo::Unpatch() {
  // We have to cast our GenericFnPtrs to void* for unpatch.  This is
  // contra the C++ spec; we use C-style casts to empahsize that.
  for (int i = 0; i < kNumFunctions; i++) {
    CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
             PreamblePatcher::Unpatch((void*)function_info_[i].windows_fn,
                                      (void*)function_info_[i].perftools_fn,
                                      (void*)function_info_[i].origstub_fn));
  }
}

// You should hold the patch_all_modules_lock when calling this.
void PatchOneModuleLocked(const LibcInfo& me_info) {
  // If we don't already have info on this module, let's add it.  This
  // is where we're sad that each libcX has a different type, so we
  // can't use an array; instead, we have to use a switch statement.
  // Patch() returns false if there were no libc functions in the module.
  for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) {
    if (!g_module_libcs[i]->is_valid()) {   // found an empty spot to add!
      switch (i) {
        case 0: libc1.Patch(me_info); return;
        case 1: libc2.Patch(me_info); return;
        case 2: libc3.Patch(me_info); return;
        case 3: libc4.Patch(me_info); return;
        case 4: libc5.Patch(me_info); return;
        case 5: libc6.Patch(me_info); return;
        case 6: libc7.Patch(me_info); return;
        case 7: libc8.Patch(me_info); return;
      }
    }
  }
  printf("PERFTOOLS ERROR: Too many modules containing libc in this executable\n");
}

void PatchMainExecutableLocked() {
  if (main_executable.patched())
    return;    // main executable has already been patched
  ModuleEntryCopy fake_module_entry;   // make a fake one to pass into Patch()
  // No need to call PopulateModuleEntryProcAddresses on the main executable.
  main_executable.PopulateWindowsFn(fake_module_entry);
  main_executable.Patch(main_executable);
}

// This lock is subject to a subtle and annoying lock inversion
// problem: it may interact badly with unknown internal windows locks.
// In particular, windows may be holding a lock when it calls
// LoadLibraryExW and FreeLibrary, which we've patched.  We have those
// routines call PatchAllModules, which acquires this lock.  If we
// make windows system calls while holding this lock, those system
// calls may need the internal windows locks that are being held in
// the call to LoadLibraryExW, resulting in deadlock.  The solution is
// to be very careful not to call *any* windows routines while holding
// patch_all_modules_lock, inside PatchAllModules().
static SpinLock patch_all_modules_lock;

// last_loaded: The set of modules that were loaded the last time
// PatchAllModules was called.  This is an optimization for only
// looking at modules that were added or removed from the last call.
static std::set *g_last_loaded;

// Iterates over all the modules currently loaded by the executable,
// according to windows, and makes sure they're all patched.  Most
// modules will already be in loaded_modules, meaning we have already
// loaded and either patched them or determined they did not need to
// be patched.  Others will not, which means we need to patch them
// (if necessary).  Finally, we have to go through the existing
// g_module_libcs and see if any of those are *not* in the modules
// currently loaded by the executable.  If so, we need to invalidate
// them.  Returns true if we did any work (patching or invalidating),
// false if we were a noop.  May update loaded_modules as well.
// NOTE: you must hold the patch_all_modules_lock to access loaded_modules.
bool PatchAllModules() {
  std::vector modules;
  bool made_changes = false;

  const HANDLE hCurrentProcess = GetCurrentProcess();
  DWORD num_modules = 0;
  HMODULE hModules[kMaxModules];  // max # of modules we support in one process
  if (!::EnumProcessModules(hCurrentProcess, hModules, sizeof(hModules),
                            &num_modules)) {
    num_modules = 0;
  }
  // EnumProcessModules actually set the bytes written into hModules,
  // so we need to divide to make num_modules actually be a module-count.
  num_modules /= sizeof(*hModules);
  if (num_modules >= kMaxModules) {
    printf("PERFTOOLS ERROR: Too many modules in this executable to try"
           " to patch them all (if you need to, raise kMaxModules in"
           " patch_functions.cc).\n");
    num_modules = kMaxModules;
  }

  // Now we handle the unpatching of modules we have in g_module_libcs
  // but that were not found in EnumProcessModules.  We need to
  // invalidate them.  To speed that up, we store the EnumProcessModules
  // output in a set.
  // At the same time, we prepare for the adding of new modules, by
  // removing from hModules all the modules we know we've already
  // patched (or decided don't need to be patched).  At the end,
  // hModules will hold only the modules that we need to consider patching.
  std::set currently_loaded_modules;
  {
    SpinLockHolder h(&patch_all_modules_lock);
    if (!g_last_loaded)  g_last_loaded = new std::set;
    // At the end of this loop, currently_loaded_modules contains the
    // full list of EnumProcessModules, and hModules just the ones we
    // haven't handled yet.
    for (int i = 0; i < num_modules; ) {
      currently_loaded_modules.insert(hModules[i]);
      if (g_last_loaded->count(hModules[i]) > 0) {
        hModules[i] = hModules[--num_modules];  // replace element i with tail
      } else {
        i++;                                    // keep element i
      }
    }
    // Now we do the unpatching/invalidation.
    for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) {
      if (g_module_libcs[i]->patched() &&
          currently_loaded_modules.count(g_module_libcs[i]->hmodule()) == 0) {
        // Means g_module_libcs[i] is no longer loaded (no me32 matched).
        // We could call Unpatch() here, but why bother?  The module
        // has gone away, so nobody is going to call into it anyway.
        g_module_libcs[i]->set_is_valid(false);
        made_changes = true;
      }
    }
    // Update the loaded module cache.
    g_last_loaded->swap(currently_loaded_modules);
  }

  // Now that we know what modules are new, let's get the info we'll
  // need to patch them.  Note this *cannot* be done while holding the
  // lock, since it needs to make windows calls (see the lock-inversion
  // comments before the definition of patch_all_modules_lock).
  MODULEINFO mi;
  for (int i = 0; i < num_modules; i++) {
    if (::GetModuleInformation(hCurrentProcess, hModules[i], &mi, sizeof(mi)))
      modules.push_back(ModuleEntryCopy(mi));
  }

  // Now we can do the patching of new modules.
  {
    SpinLockHolder h(&patch_all_modules_lock);
    for (std::vector::iterator it = modules.begin();
         it != modules.end(); ++it) {
      LibcInfo libc_info;
      if (libc_info.PopulateWindowsFn(*it)) { // true==module has libc routines
        PatchOneModuleLocked(libc_info);
        made_changes = true;
      }
    }

    // Now that we've dealt with the modules (dlls), update the main
    // executable.  We do this last because PatchMainExecutableLocked
    // wants to look at how other modules were patched.
    if (!main_executable.patched()) {
      PatchMainExecutableLocked();
      made_changes = true;
    }
  }
  // TODO(csilvers): for this to be reliable, we need to also take
  // into account if we *would* have patched any modules had they not
  // already been loaded.  (That is, made_changes should ignore
  // g_last_loaded.)
  return made_changes;
}


}  // end unnamed namespace

// ---------------------------------------------------------------------
// Now that we've done all the patching machinery, let's actually
// define the functions we're patching in.  Mostly these are
// simple wrappers around the do_* routines in tcmalloc.cc.
//
// In fact, we #include tcmalloc.cc to get at the tcmalloc internal
// do_* functions, the better to write our own hook functions.
// U-G-L-Y, I know.  But the alternatives are, perhaps, worse.  This
// also lets us define _msize(), _expand(), and other windows-specific
// functions here, using tcmalloc internals, without polluting
// tcmalloc.cc.
// -------------------------------------------------------------------

// TODO(csilvers): refactor tcmalloc.cc into two files, so I can link
// against the file with do_malloc, and ignore the one with malloc.
#include "tcmalloc.cc"

template
void* LibcInfoWithPatchFunctions::Perftools_malloc(size_t size) __THROW {
  return malloc_fast_path(size);
}

template
void LibcInfoWithPatchFunctions::Perftools_free(void* ptr) __THROW {
  tcmalloc::InvokeDeleteHook(ptr);
  // This calls the windows free if do_free decides ptr was not
  // allocated by tcmalloc.  Note it calls the origstub_free from
  // *this* templatized instance of LibcInfo.  See "template
  // trickiness" above.
  do_free_with_callback(ptr, (void (*)(void*))origstub_fn_[kFree], false, 0);
}

template
void LibcInfoWithPatchFunctions::Perftools_free_base(void* ptr) __THROW{
  tcmalloc::InvokeDeleteHook(ptr);
  // This calls the windows free if do_free decides ptr was not
  // allocated by tcmalloc.  Note it calls the origstub_free from
  // *this* templatized instance of LibcInfo.  See "template
  // trickiness" above.
  do_free_with_callback(ptr, (void(*)(void*))origstub_fn_[kFreeBase], false, 0);
}

template
void LibcInfoWithPatchFunctions::Perftools_free_dbg(void* ptr, int block_use) __THROW {
  tcmalloc::InvokeDeleteHook(ptr);
  // The windows _free_dbg is called if ptr isn't owned by tcmalloc.
  if (MallocExtension::instance()->GetOwnership(ptr) == MallocExtension::kOwned) {
    do_free(ptr);
  } else {
    reinterpret_cast(origstub_fn_[kFreeDbg])(ptr, block_use);
  }
}

template
void* LibcInfoWithPatchFunctions::Perftools_realloc(
    void* old_ptr, size_t new_size) __THROW {
  if (old_ptr == nullptr) {
    void* result = do_malloc_or_cpp_alloc(new_size);
    tcmalloc::InvokeNewHook(result, new_size);
    return result;
  }
  if (new_size == 0) {
    tcmalloc::InvokeDeleteHook(old_ptr);
    do_free_with_callback(old_ptr,
                          (void (*)(void*))origstub_fn_[kFree], false, 0);
    return nullptr;
  }
  return do_realloc_with_callback(
      old_ptr, new_size,
      (void (*)(void*))origstub_fn_[kFree],
      (size_t (*)(const void*))origstub_fn_[k_Msize]);
}

template
void* LibcInfoWithPatchFunctions::Perftools_calloc(
    size_t n, size_t elem_size) __THROW {
  void* result = do_calloc(n, elem_size);
  tcmalloc::InvokeNewHook(result, n * elem_size);
  return result;
}

template
void* LibcInfoWithPatchFunctions::Perftools_new(size_t size) {
  return malloc_fast_path(size);
}

template
void* LibcInfoWithPatchFunctions::Perftools_newarray(size_t size) {
  return malloc_fast_path(size);
}

template
void LibcInfoWithPatchFunctions::Perftools_delete(void *p) {
  tcmalloc::InvokeDeleteHook(p);
  do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree], false, 0);
}

template
void LibcInfoWithPatchFunctions::Perftools_deletearray(void *p) {
  tcmalloc::InvokeDeleteHook(p);
  do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree], false, 0);
}

template
void* LibcInfoWithPatchFunctions::Perftools_new_nothrow(
    size_t size, const std::nothrow_t&) __THROW {
  return malloc_fast_path(size);
}

template
void* LibcInfoWithPatchFunctions::Perftools_newarray_nothrow(
    size_t size, const std::nothrow_t&) __THROW {
  return malloc_fast_path(size);
}

template
void LibcInfoWithPatchFunctions::Perftools_delete_nothrow(
    void *p, const std::nothrow_t&) __THROW {
  tcmalloc::InvokeDeleteHook(p);
  do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree], false, 0);
}

template
void LibcInfoWithPatchFunctions::Perftools_deletearray_nothrow(
    void *p, const std::nothrow_t&) __THROW {
  tcmalloc::InvokeDeleteHook(p);
  do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree], false, 0);
}


// _msize() lets you figure out how much space is reserved for a
// pointer, in Windows.  Even if applications don't call it, any DLL
// with global constructors will call (transitively) something called
// __dllonexit_lk in order to make sure the destructors get called
// when the dll unloads.  And that will call msize -- horrible things
// can ensue if this is not hooked.  Other parts of libc may also call
// this internally.

template
size_t LibcInfoWithPatchFunctions::Perftools__msize(void* ptr) __THROW {
  return GetSizeWithCallback(ptr, (size_t (*)(const void*))origstub_fn_[k_Msize]);
}

LPVOID WINAPI WindowsInfo::Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags,
                                               DWORD_PTR dwBytes) {
  LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD_PTR))
                   function_info_[kHeapAlloc].origstub_fn)(
                       hHeap, dwFlags, dwBytes);
  tcmalloc::InvokeNewHook(result, dwBytes);
  return result;
}

BOOL WINAPI WindowsInfo::Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags,
                                            LPVOID lpMem) {
  tcmalloc::InvokeDeleteHook(lpMem);

  // We perform this check to work around a malloc/HeapFree mismatch
  // in shell32.dll versions [10.0.22000.0, 10.0.22621.900)
  // See issue #1490 for more context and oneapi-src/oneTBB #665
  // for a full breakdown
  bool owned_by_tcmalloc = MallocExtension::instance()->GetOwnership(lpMem) == MallocExtension::kOwned;

  if (!owned_by_tcmalloc) {
    return ((BOOL (WINAPI *)(HANDLE, DWORD, LPVOID))
            function_info_[kHeapFree].origstub_fn)(
                hHeap, dwFlags, lpMem);
  } else {
    do_free(lpMem);
    return true;
  }
}

HMODULE WINAPI WindowsInfo::Perftools_LoadLibraryExW(LPCWSTR lpFileName,
                                                     HANDLE hFile,
                                                     DWORD dwFlags) {
  HMODULE rv;
  // Check to see if the modules is already loaded, flag 0 gets a
  // reference if it was loaded.  If it was loaded no need to call
  // PatchAllModules, just increase the reference count to match
  // what GetModuleHandleExW does internally inside windows.
  if (::GetModuleHandleExW(0, lpFileName, &rv)) {
    return rv;
  } else {
    // Not already loaded, so load it.
    rv = ((HMODULE (WINAPI *)(LPCWSTR, HANDLE, DWORD))
                  function_info_[kLoadLibraryExW].origstub_fn)(
                      lpFileName, hFile, dwFlags);
    // This will patch any newly loaded libraries, if patching needs
    // to be done.
    PatchAllModules();

    return rv;
  }
}

BOOL WINAPI WindowsInfo::Perftools_FreeLibrary(HMODULE hLibModule) {
  BOOL rv = ((BOOL (WINAPI *)(HMODULE))
             function_info_[kFreeLibrary].origstub_fn)(hLibModule);

  // Check to see if the module is still loaded by passing the base
  // address and seeing if it comes back with the same address.  If it
  // is the same address it's still loaded, so the FreeLibrary() call
  // was a noop, and there's no need to redo the patching.
  HMODULE owner = nullptr;
  BOOL result = ::GetModuleHandleExW(
      (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
       GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
      (LPCWSTR)hLibModule,
      &owner);
  if (result && owner == hLibModule)
    return rv;

  PatchAllModules();    // this will fix up the list of patched libraries
  return rv;
}


// ---------------------------------------------------------------------
// PatchWindowsFunctions()
//    This is the function that is exposed to the outside world.
//    It should be called before the program becomes multi-threaded,
//    since main_executable_windows.Patch() is not thread-safe.
// ---------------------------------------------------------------------

void PatchWindowsFunctions() {
  const char* disable_env = TCMallocGetenvSafe("TCMALLOC_DISABLE_REPLACEMENT");
  const bool should_skip = disable_env &&
                           disable_env[0] == '1' &&
                           disable_env[1] == '\0';

  if (!should_skip) {
    // This does the libc patching in every module, and the main executable.
    PatchAllModules();
    main_executable_windows.Patch();
  }
}

#if 0
// It's possible to unpatch all the functions when we are exiting.

// The idea is to handle properly windows-internal data that is
// allocated before PatchWindowsFunctions is called.  If all
// destruction happened in reverse order from construction, then we
// could call UnpatchWindowsFunctions at just the right time, so that
// that early-allocated data would be freed using the windows
// allocation functions rather than tcmalloc.  The problem is that
// windows allocates some structures lazily, so it would allocate them
// late (using tcmalloc) and then try to deallocate them late as well.
// So instead of unpatching, we just modify all the tcmalloc routines
// so they call through to the libc rountines if the memory in
// question doesn't seem to have been allocated with tcmalloc.  I keep
// this unpatch code around for reference.

void UnpatchWindowsFunctions() {
  // We need to go back to the system malloc/etc at global destruct time,
  // so objects that were constructed before tcmalloc, using the system
  // malloc, can destroy themselves using the system free.  This depends
  // on DLLs unloading in the reverse order in which they load!
  //
  // We also go back to the default HeapAlloc/etc, just for consistency.
  // Who knows, it may help avoid weird bugs in some situations.
  main_executable_windows.Unpatch();
  main_executable.Unpatch();
  if (libc1.is_valid()) libc1.Unpatch();
  if (libc2.is_valid()) libc2.Unpatch();
  if (libc3.is_valid()) libc3.Unpatch();
  if (libc4.is_valid()) libc4.Unpatch();
  if (libc5.is_valid()) libc5.Unpatch();
  if (libc6.is_valid()) libc6.Unpatch();
  if (libc7.is_valid()) libc7.Unpatch();
  if (libc8.is_valid()) libc8.Unpatch();
}
#endif
gperftools-gperftools-2.18/src/windows/port.cc000066400000000000000000000213001513545575200215760ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Craig Silverstein
 */

#ifndef _WIN32
# error You should only be including windows/port.cc in a windows environment!
#endif

#include "config.h"

#include     // for strlen(), memset(), memcmp()
#include 
#include     // for va_list, va_start, va_end
#include    // for std:{min,max}
#include 
#include "port.h"
#include "base/logging.h"
#include "base/spinlock.h"
#include "base/threading.h"
#include "internal_logging.h"

// -----------------------------------------------------------------------
// Basic libraries

PERFTOOLS_DLL_DECL
int getpagesize() {
  static int pagesize = 0;
  if (pagesize == 0) {
    SYSTEM_INFO system_info;
    GetSystemInfo(&system_info);
    pagesize = std::max(system_info.dwPageSize,
                        system_info.dwAllocationGranularity);
  }
  return pagesize;
}

// 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
// require memory allocation.
extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) {
  // Looks like windows allocates for writes of >80 bytes
  for (int i = 0; i < len; i += 80) {
    write(STDERR_FILENO, buf + i, std::min(80, len - i));
  }
}


// -----------------------------------------------------------------------
// Threads code

// Windows doesn't support tcmalloc::CreateTlsKey's destr_function, and in
// fact it's a bit tricky to get code to run when a thread exits.  This
// is cargo-cult magic from https://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
// and http://lallouslab.net/2017/05/30/using-cc-tls-callbacks-in-visual-studio-with-your-32-or-64bits-programs/.
// This code is for VC++ 7.1 and later; VC++ 6.0 support is possible
// but more busy-work -- see the webpage for how to do it.  If all
// this fails, we could use DllMain instead.  The big problem with
// DllMain is it doesn't run if this code is statically linked into a
// binary (it also doesn't run if the thread is terminated via
// TerminateThread, which if we're lucky this routine does).

// Force a reference to _tls_used to make the linker create the TLS directory
// if it's not already there (that is, even if __declspec(thread) is not used).
// Force a reference to p_thread_callback_tcmalloc and p_process_term_tcmalloc
// to prevent whole program optimization from discarding the variables.
#ifdef _MSC_VER
#if defined(_M_IX86)
#pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:_p_thread_callback_tcmalloc")
#pragma comment(linker, "/INCLUDE:_p_process_term_tcmalloc")
#elif defined(_M_X64)
#pragma comment(linker, "/INCLUDE:_tls_used")
#pragma comment(linker, "/INCLUDE:p_thread_callback_tcmalloc")
#pragma comment(linker, "/INCLUDE:p_process_term_tcmalloc")
#endif
#endif

// When destr_fn eventually runs, it's supposed to take as its
// argument the tls-value associated with key that tcmalloc::CreateTlsKey
// creates.  (Yeah, it sounds confusing but it's really not.)  We
// store the destr_fn/key pair in this data structure.  Because we
// store this in a single var, this implies we can only have one
// destr_fn in a program!  That's enough in practice.  If asserts
// trigger because we end up needing more, we'll have to turn this
// into an array.
struct DestrFnClosure {
  void (*destr_fn)(void*);
  tcmalloc::TlsKey key_for_destr_fn_arg;
};

static DestrFnClosure destr_fn_info;   // initted to all nullptr/0.

static int on_process_term(void) {
  if (destr_fn_info.destr_fn) {
    void *ptr = TlsGetValue(destr_fn_info.key_for_destr_fn_arg);
    // This shouldn't be necessary, but in Release mode, Windows
    // sometimes trashes the pointer in the TLS slot, so we need to
    // remove the pointer from the TLS slot before the thread dies.
    TlsSetValue(destr_fn_info.key_for_destr_fn_arg, nullptr);
    if (ptr)  // pthread semantics say not to call if ptr is nullptr
      (*destr_fn_info.destr_fn)(ptr);
  }
  return 0;
}

static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) {
  if (dwReason == DLL_THREAD_DETACH) {   // thread is being destroyed!
    on_process_term();
  }
}

#ifdef _MSC_VER

// extern "C" suppresses C++ name mangling so we know the symbol names
// for the linker /INCLUDE:symbol pragmas above.
// Note that for some unknown reason, the extern "C" {} construct is ignored
// by the MSVC VS2017 compiler (at least) when a const modifier is used
#if defined(_M_IX86)
extern "C" {
// In x86, the PE loader looks for callbacks in a data segment
#pragma data_seg(push, old_seg)
#pragma data_seg(".CRT$XLB")
void (NTAPI *p_thread_callback_tcmalloc)(
    HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback;
#pragma data_seg(".CRT$XTU")
int (*p_process_term_tcmalloc)(void) = on_process_term;
#pragma data_seg(pop, old_seg)
}  // extern "C"
#elif defined(_M_X64)
// In x64, the PE loader looks for callbacks in a constant segment
#pragma const_seg(push, oldseg)
#pragma const_seg(".CRT$XLB")
extern "C" void (NTAPI * const p_thread_callback_tcmalloc)(
	HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback;
#pragma const_seg(".CRT$XTU")
extern "C" int (NTAPI * const p_process_term_tcmalloc)(void) = on_process_term;
#pragma const_seg(pop, oldseg)
#endif

#else  // #ifdef _MSC_VER  [probably msys/mingw]

// We have to try the DllMain solution here, because we can't use the
// msvc-specific pragmas.
BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) {
  if (dwReason == DLL_THREAD_DETACH)
    on_tls_callback(h, dwReason, pv);
  else if (dwReason == DLL_PROCESS_DETACH)
    on_process_term();
  return TRUE;
}

#endif  // #ifdef _MSC_VER

tcmalloc::TlsKey tcmalloc::WinTlsKeyCreate(void (*destr_fn)(void*)) {
  // Semantics are: we create a new key, and then promise to call
  // destr_fn with TlsGetValue(key) when the thread is destroyed
  // (as long as TlsGetValue(key) is not nullptr).
  tcmalloc::TlsKey key = TlsAlloc();
  if (destr_fn) {   // register it
    // If this assert fails, we'll need to support an array of destr_fn_infos
    assert(destr_fn_info.destr_fn == nullptr);
    destr_fn_info.destr_fn = destr_fn;
    destr_fn_info.key_for_destr_fn_arg = key;
  }
  return key;
}

// -----------------------------------------------------------------------
// These functions rework existing functions of the same name in the
// Google codebase.

// A replacement for HeapProfiler::CleanupOldProfiles.
void DeleteMatchingFiles(const char* prefix, const char* full_glob) {
  WIN32_FIND_DATAA found;  // that final A is for Ansi (as opposed to Unicode)
  HANDLE hFind = FindFirstFileA(full_glob, &found);   // A is for Ansi
  if (hFind != INVALID_HANDLE_VALUE) {
    const int prefix_length = strlen(prefix);
    do {
      const char *fname = found.cFileName;
      if ((strlen(fname) >= prefix_length) &&
          (memcmp(fname, prefix, prefix_length) == 0)) {
        RAW_VLOG(0, "Removing old heap profile %s\n", fname);
        // TODO(csilvers): we really need to unlink dirname + fname
        _unlink(fname);
      }
    } while (FindNextFileA(hFind, &found) != FALSE);  // A is for Ansi
    FindClose(hFind);
  }
}
gperftools-gperftools-2.18/src/windows/port.h000066400000000000000000000225711513545575200214530ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Craig Silverstein
 *
 * These are some portability typedefs and defines to make it a bit
 * easier to compile this code under VC++.
 *
 * Several of these are taken from glib:
 *    http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
 */

#ifndef GOOGLE_BASE_WINDOWS_H_
#define GOOGLE_BASE_WINDOWS_H_

/* You should never include this file directly, but always include it from config.h */
#ifndef GPERFTOOLS_CONFIG_H_
# error "port.h should only be included from config.h"
#endif

#ifdef _WIN32

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN  /* We always want minimal includes */
#endif

// windows.h whatevevs defines min and max preprocessor macros and
// that breaks ::max() in various places (like numeric_limits)
#ifndef NOMINMAX
#define NOMINMAX
#endif

// Our spinlock futex-like wait support depends on windows 8
// feature. So we ask for windows 8 APIs.
//
// https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=msvc-170
#ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0602
#endif

#if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0700
// Older version of the mingw msvcrt don't define _aligned_malloc
# define PERFTOOLS_NO_ALIGNED_MALLOC 1
#endif

#include 
#include               /* because we so often use open/close/etc */
#include           /* for _getcwd */
#include          /* for _getpid */
#include           /* for PATH_MAX */
#include           /* for va_list */
#include            /* need this to override stdio's (v)snprintf */
#include        /* for _off_t */
#include 
#include           /* for rand, srand, _strtoxxx */

#if defined(_MSC_VER) && _MSC_VER >= 1900
#define _TIMESPEC_DEFINED
#include 
#endif

/*
 * 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned_i)
 * 4244: otherwise we get problems when subtracting two size_t's to an int
 * 4288: VC++7 gets confused when a var is defined in a loop and then after it
 * 4267: too many false positives for "conversion gives possible data loss"
 * 4290: it's ok windows ignores the "throw" directive
 * 4996: Yes, we're ok using "unsafe" functions like vsnprintf and getenv()
 * 4146: internal_logging.cc intentionally negates an unsigned value
 */
#ifdef _MSC_VER
#pragma warning(disable:4018 4244 4288 4267 4290 4996 4146)
#endif

#ifndef __cplusplus
/* MSVC does not support C99 */
# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
#  ifdef _MSC_VER
#    define inline __inline
#  else
#    define inline static
#  endif
# endif
#endif

#ifdef __cplusplus
# define EXTERN_C  extern "C"
#else
# define EXTERN_C  extern
#endif

/* ----------------------------------- BASIC TYPES */

/* I guess MSVC's  doesn't include ssize_t by default? */
#ifdef _MSC_VER
typedef intptr_t ssize_t;
#endif

/* ----------------------------------- THREADS */

/*
 * __declspec(thread) isn't usable in a dll opened via LoadLibrary().
 * But it doesn't work to LoadLibrary() us anyway, because of all the
 * things we need to do before main()!  So this kind of TLS is safe for us.
 */
#define __thread __declspec(thread)

/* ----------------------------------- MMAP and other memory allocation */

#ifndef HAVE_MMAP   /* not true for MSVC, but may be true for msys */
#define MAP_FAILED  0
#define MREMAP_FIXED  2  /* the value in linux, though it doesn't really matter */
/* These, when combined with the mmap invariants below, yield the proper action */
#define PROT_READ      PAGE_READWRITE
#define PROT_WRITE     PAGE_READWRITE
#define MAP_ANONYMOUS  MEM_RESERVE
#define MAP_PRIVATE    MEM_COMMIT
#define MAP_SHARED     MEM_RESERVE   /* value of this #define is 100% arbitrary */

#if __STDC__ && !defined(__MINGW32__)
typedef _off_t off_t;
#endif

/* VirtualAlloc only replaces for mmap when certain invariants are kept. */
inline void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset) {
  if (addr == nullptr && fd == -1 && offset == 0 &&
      prot == (PROT_READ|PROT_WRITE) && flags == (MAP_PRIVATE|MAP_ANONYMOUS)) {
    return VirtualAlloc(0, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  } else {
    return nullptr;
  }
}

inline int munmap(void *addr, size_t length) {
  return VirtualFree(addr, 0, MEM_RELEASE) ? 0 : -1;
}
#endif  /* HAVE_MMAP */

/* We could maybe use VirtualAlloc for sbrk as well, but no need */
inline void *sbrk(intptr_t increment) {
  // sbrk returns -1 on failure
  return (void*)-1;
}


/* ----------------------------------- FILE IO */

#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#ifndef __MINGW32__
enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
#endif
#ifndef O_RDONLY
#define O_RDONLY  _O_RDONLY
#endif

#if __STDC__ && !defined(__MINGW32__)
/* These functions are considered non-standard */
inline int access(const char *pathname, int mode) {
  return _access(pathname, mode);
}
inline int open(const char *pathname, int flags, int mode = 0) {
  return _open(pathname, flags, mode);
}
inline int close(int fd) {
  return _close(fd);
}
inline ssize_t read(int fd, void *buf, size_t count) {
  return _read(fd, buf, count);
}
inline ssize_t write(int fd, const void *buf, size_t count) {
  return _write(fd, buf, count);
}
inline off_t lseek(int fd, off_t offset, int whence) {
  return _lseek(fd, offset, whence);
}
inline char *getcwd(char *buf, size_t size) {
  return _getcwd(buf, size);
}
inline int mkdir(const char *pathname, int) {
  return _mkdir(pathname);
}

inline FILE *popen(const char *command, const char *type) {
  return _popen(command, type);
}
inline int pclose(FILE *stream) {
  return _pclose(stream);
}
#endif

EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len);

/* ----------------------------------- SYSTEM/PROCESS */

/* Handle case when poll is used to simulate sleep. */
inline int poll(struct pollfd* fds, int nfds, int timeout) {
  assert(fds == nullptr);
  assert(nfds == 0);
  Sleep(timeout);
  return 0;
}

EXTERN_C PERFTOOLS_DLL_DECL int getpagesize();   /* in port.cc */

/* ----------------------------------- OTHER */

inline void srandom(unsigned int seed) { srand(seed); }
inline long random(void) { return rand(); }

#ifndef HAVE_DECL_SLEEP
#define HAVE_DECL_SLEEP 0
#endif

#if !HAVE_DECL_SLEEP
inline unsigned int sleep(unsigned int seconds) {
  Sleep(seconds * 1000);
  return 0;
}
#endif

// mingw64 seems to define timespec (though mingw.org mingw doesn't),
// protected by the _TIMESPEC_DEFINED macro.
#ifndef _TIMESPEC_DEFINED
struct timespec {
  int tv_sec;
  int tv_nsec;
};
#endif

#ifndef HAVE_DECL_NANOSLEEP
#define HAVE_DECL_NANOSLEEP 0
#endif

// latest mingw64 has nanosleep. Earlier mingw and MSVC do not
#if !HAVE_DECL_NANOSLEEP
inline int nanosleep(const struct timespec *req, struct timespec *rem) {
  Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000);
  return 0;
}
#endif

#ifndef __MINGW32__
#if defined(_MSC_VER) && _MSC_VER < 1800
inline long long int strtoll(const char *nptr, char **endptr, int base) {
    return _strtoi64(nptr, endptr, base);
}
inline unsigned long long int strtoull(const char *nptr, char **endptr,
                                       int base) {
    return _strtoui64(nptr, endptr, base);
}
inline long long int strtoq(const char *nptr, char **endptr, int base) {
    return _strtoi64(nptr, endptr, base);
}
#endif
inline unsigned long long int strtouq(const char *nptr, char **endptr,
                                      int base) {
    return _strtoui64(nptr, endptr, base);
}
inline long long atoll(const char *nptr) {
  return _atoi64(nptr);
}
#endif

#define __THROW throw()

/* ----------------------------------- TCMALLOC-SPECIFIC */

/* tcmalloc.cc calls this so we can patch VirtualAlloc() et al. */
extern void PatchWindowsFunctions();

#endif  /* _WIN32 */

#undef inline
#undef EXTERN_C

#endif  /* GOOGLE_BASE_WINDOWS_H_ */
gperftools-gperftools-2.18/src/windows/preamble_patcher.cc000066400000000000000000000710431513545575200241200ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 * Author: Scott Francis
 *
 * Implementation of PreamblePatcher
 */

#include "preamble_patcher.h"

#include "mini_disassembler.h"

// compatibility shims
#include "base/logging.h"

// Definitions of assembly statements we need
#define ASM_JMP32REL 0xE9
#define ASM_INT3 0xCC
#define ASM_JMP32ABS_0 0xFF
#define ASM_JMP32ABS_1 0x25
#define ASM_JMP8REL 0xEB
#define ASM_JCC32REL_0 0x0F
#define ASM_JCC32REL_1_MASK 0x80
#define ASM_NOP 0x90
// X64 opcodes
#define ASM_REXW 0x48
#define ASM_MOVRAX_IMM 0xB8
#define ASM_JMP 0xFF
#define ASM_JMP_RAX 0xE0

namespace sidestep {

PreamblePatcher::PreamblePage* PreamblePatcher::preamble_pages_;
long PreamblePatcher::granularity_;
long PreamblePatcher::pagesize_;
bool PreamblePatcher::initialized_;

static const unsigned int kPreamblePageMagic = 0x4347414D; // "MAGC"

// Handle a special case that we see with functions that point into an
// IAT table (including functions linked statically into the
// application): these function already starts with ASM_JMP32*.  For
// instance, malloc() might be implemented as a JMP to __malloc().
// This function follows the initial JMPs for us, until we get to the
// place where the actual code is defined.  If we get to STOP_BEFORE,
// we return the address before stop_before.  The stop_before_trampoline
// flag is used in 64-bit mode.  If true, we will return the address
// before a trampoline is detected.  Trampolines are defined as:
//
//    nop
//    mov rax, 
//    jmp rax
//
// See PreamblePatcher::RawPatchWithStub for more information.
void* PreamblePatcher::ResolveTargetImpl(unsigned char* target,
                                         unsigned char* stop_before,
                                         bool stop_before_trampoline) {
  if (target == nullptr)
    return nullptr;
  while (1) {
    unsigned char* new_target;
    if (target[0] == ASM_JMP32REL) {
      // target[1-4] holds the place the jmp goes to, but it's
      // relative to the next instruction.
      int relative_offset;   // Windows guarantees int is 4 bytes
      SIDESTEP_ASSERT(sizeof(relative_offset) == 4);
      memcpy(reinterpret_cast(&relative_offset),
             reinterpret_cast(target + 1), 4);
      new_target = target + 5 + relative_offset;
    } else if (target[0] == ASM_JMP8REL) {
      // Visual Studio 7.1 implements new[] as an 8 bit jump to new
      signed char relative_offset;
      memcpy(reinterpret_cast(&relative_offset),
             reinterpret_cast(target + 1), 1);
      new_target = target + 2 + relative_offset;
    } else if (target[0] == ASM_JMP32ABS_0 &&
               target[1] == ASM_JMP32ABS_1) {
    jmp32rel:
      // Visual studio seems to sometimes do it this way instead of the
      // previous way.  Not sure what the rules are, but it was happening
      // with operator new in some binaries.
      void** new_target_v;
      if (kIs64BitBinary) {
        // In 64-bit mode JMPs are RIP-relative, not absolute
        int target_offset;
        memcpy(reinterpret_cast(&target_offset),
               reinterpret_cast(target + 2), 4);
        new_target_v = reinterpret_cast(target + target_offset + 6);
      } else {
        SIDESTEP_ASSERT(sizeof(new_target) == 4);
        memcpy(&new_target_v, reinterpret_cast(target + 2), 4);
      }
      new_target = reinterpret_cast(*new_target_v);
    } else if (kIs64BitBinary && target[0] == ASM_REXW
               && target[1] == ASM_JMP32ABS_0
               && target[2] == ASM_JMP32ABS_1) {
      // in Visual Studio 2012 we're seeing jump like that:
      //   rex.W jmpq *0x11d019(%rip)
      //
      // according to docs I have, rex prefix is actually unneeded and
      // can be ignored. I.e. docs say for jumps like that operand
      // already defaults to 64-bit. But clearly it breaks abs. jump
      // detection above and we just skip rex
      target++;
      goto jmp32rel;
    } else {
      break;
    }
    if (new_target == stop_before)
      break;
    if (stop_before_trampoline && *new_target == ASM_NOP
        && new_target[1] == ASM_REXW && new_target[2] == ASM_MOVRAX_IMM)
      break;
    target = new_target;
  }
  return target;
}

// Special case scoped_ptr to avoid dependency on scoped_ptr below.
class DeleteUnsignedCharArray {
 public:
  DeleteUnsignedCharArray(unsigned char* array) : array_(array) {
  }

  ~DeleteUnsignedCharArray() {
    if (array_) {
      PreamblePatcher::FreePreambleBlock(array_);
    }
  }

  unsigned char* Release() {
    unsigned char* temp = array_;
    array_ = nullptr;
    return temp;
  }

 private:
  unsigned char* array_;
};

SideStepError PreamblePatcher::RawPatchWithStubAndProtections(
    void* target_function, void *replacement_function,
    unsigned char* preamble_stub, unsigned long stub_size,
    unsigned long* bytes_needed) {
  // We need to be able to write to a process-local copy of the first
  // MAX_PREAMBLE_STUB_SIZE bytes of target_function
  DWORD old_target_function_protect = 0;
  BOOL succeeded = ::VirtualProtect(reinterpret_cast(target_function),
                                    MAX_PREAMBLE_STUB_SIZE,
                                    PAGE_EXECUTE_READWRITE,
                                    &old_target_function_protect);
  if (!succeeded) {
    SIDESTEP_ASSERT(false && "Failed to make page containing target function "
                    "copy-on-write.");
    return SIDESTEP_ACCESS_DENIED;
  }

  SideStepError error_code = RawPatchWithStub(target_function,
                                              replacement_function,
                                              preamble_stub,
                                              stub_size,
                                              bytes_needed);

  // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of
  // pTargetFunction to what they were before we started goofing around.
  // We do this regardless of whether the patch succeeded or not.
  succeeded = ::VirtualProtect(reinterpret_cast(target_function),
                               MAX_PREAMBLE_STUB_SIZE,
                               old_target_function_protect,
                               &old_target_function_protect);
  if (!succeeded) {
    SIDESTEP_ASSERT(false &&
                    "Failed to restore protection to target function.");
    // We must not return an error here because the function has
    // likely actually been patched, and returning an error might
    // cause our client code not to unpatch it.  So we just keep
    // going.
  }

  if (SIDESTEP_SUCCESS != error_code) {  // Testing RawPatchWithStub, above
    SIDESTEP_ASSERT(false);
    return error_code;
  }

  // Flush the instruction cache to make sure the processor doesn't execute the
  // old version of the instructions (before our patch).
  //
  // FlushInstructionCache is actually a no-op at least on
  // single-processor XP machines.  I'm not sure why this is so, but
  // it is, yet I want to keep the call to the API here for
  // correctness in case there is a difference in some variants of
  // Windows/hardware.
  succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
                                      target_function,
                                      MAX_PREAMBLE_STUB_SIZE);
  if (!succeeded) {
    SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
    // We must not return an error here because the function has actually
    // been patched, and returning an error would likely cause our client
    // code not to unpatch it.  So we just keep going.
  }

  return SIDESTEP_SUCCESS;
}

SideStepError PreamblePatcher::RawPatch(void* target_function,
                                        void* replacement_function,
                                        void** original_function_stub) {
  if (!target_function || !replacement_function || !original_function_stub ||
      (*original_function_stub) || target_function == replacement_function) {
    SIDESTEP_ASSERT(false && "Preconditions not met");
    return SIDESTEP_INVALID_PARAMETER;
  }

  BOOL succeeded = FALSE;

  // First, deal with a special case that we see with functions that
  // point into an IAT table (including functions linked statically
  // into the application): these function already starts with
  // ASM_JMP32REL.  For instance, malloc() might be implemented as a
  // JMP to __malloc().  In that case, we replace the destination of
  // the JMP (__malloc), rather than the JMP itself (malloc).  This
  // way we get the correct behavior no matter how malloc gets called.
  void* new_target = ResolveTarget(target_function);
  if (new_target != target_function) {
    target_function = new_target;
  }

  // In 64-bit mode, preamble_stub must be within 2GB of target function
  // so that if target contains a jump, we can translate it.
  unsigned char* preamble_stub = AllocPreambleBlockNear(target_function);
  if (!preamble_stub) {
    SIDESTEP_ASSERT(false && "Unable to allocate preamble-stub.");
    return SIDESTEP_INSUFFICIENT_BUFFER;
  }

  // Frees the array at end of scope.
  DeleteUnsignedCharArray guard_preamble_stub(preamble_stub);

  SideStepError error_code = RawPatchWithStubAndProtections(
      target_function, replacement_function, preamble_stub,
      MAX_PREAMBLE_STUB_SIZE, nullptr);

  if (SIDESTEP_SUCCESS != error_code) {
    SIDESTEP_ASSERT(false);
    return error_code;
  }

  // Flush the instruction cache to make sure the processor doesn't execute the
  // old version of the instructions (before our patch).
  //
  // FlushInstructionCache is actually a no-op at least on
  // single-processor XP machines.  I'm not sure why this is so, but
  // it is, yet I want to keep the call to the API here for
  // correctness in case there is a difference in some variants of
  // Windows/hardware.
  succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
                                      target_function,
                                      MAX_PREAMBLE_STUB_SIZE);
  if (!succeeded) {
    SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
    // We must not return an error here because the function has actually
    // been patched, and returning an error would likely cause our client
    // code not to unpatch it.  So we just keep going.
  }

  SIDESTEP_LOG("PreamblePatcher::RawPatch successfully patched.");

  // detach the scoped pointer so the memory is not freed
  *original_function_stub =
      reinterpret_cast(guard_preamble_stub.Release());
  return SIDESTEP_SUCCESS;
}

SideStepError PreamblePatcher::Unpatch(void* target_function,
                                       void* replacement_function,
                                       void* original_function_stub) {
  SIDESTEP_ASSERT(target_function && replacement_function &&
                  original_function_stub);
  if (!target_function || !replacement_function ||
      !original_function_stub) {
    return SIDESTEP_INVALID_PARAMETER;
  }

  // Before unpatching, target_function should be a JMP to
  // replacement_function.  If it's not, then either it's an error, or
  // we're falling into the case where the original instruction was a
  // JMP, and we patched the jumped_to address rather than the JMP
  // itself.  (For instance, if malloc() is just a JMP to __malloc(),
  // we patched __malloc() and not malloc().)
  unsigned char* target = reinterpret_cast(target_function);
  target = reinterpret_cast(
      ResolveTargetImpl(
          target, reinterpret_cast(replacement_function),
          true));
  // We should end at the function we patched.  When we patch, we insert
  // a ASM_JMP32REL instruction, so look for that as a sanity check.
  if (target[0] != ASM_JMP32REL) {
    SIDESTEP_ASSERT(false &&
                    "target_function does not look like it was patched.");
    return SIDESTEP_INVALID_PARAMETER;
  }

  const unsigned int kRequiredTargetPatchBytes = 5;

  // We need to be able to write to a process-local copy of the first
  // kRequiredTargetPatchBytes bytes of target_function
  DWORD old_target_function_protect = 0;
  BOOL succeeded = ::VirtualProtect(reinterpret_cast(target),
                                    kRequiredTargetPatchBytes,
                                    PAGE_EXECUTE_READWRITE,
                                    &old_target_function_protect);
  if (!succeeded) {
    SIDESTEP_ASSERT(false && "Failed to make page containing target function "
                    "copy-on-write.");
    return SIDESTEP_ACCESS_DENIED;
  }

  unsigned char* preamble_stub = reinterpret_cast(
                                   original_function_stub);

  // Disassemble the preamble of stub and copy the bytes back to target.
  // If we've done any conditional jumps in the preamble we need to convert
  // them back to the original REL8 jumps in the target.
  MiniDisassembler disassembler;
  unsigned int preamble_bytes = 0;
  unsigned int target_bytes = 0;
  while (target_bytes < kRequiredTargetPatchBytes) {
    unsigned int cur_bytes = 0;
    InstructionType instruction_type =
        disassembler.Disassemble(preamble_stub + preamble_bytes, cur_bytes);
    if (IT_JUMP == instruction_type) {
      unsigned int jump_bytes = 0;
      SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION;
      if (IsNearConditionalJump(preamble_stub + preamble_bytes, cur_bytes) ||
          IsNearRelativeJump(preamble_stub + preamble_bytes, cur_bytes) ||
          IsNearAbsoluteCall(preamble_stub + preamble_bytes, cur_bytes) ||
          IsNearRelativeCall(preamble_stub + preamble_bytes, cur_bytes)) {
        jump_ret = PatchNearJumpOrCall(preamble_stub + preamble_bytes,
                                       cur_bytes, target + target_bytes,
                                       &jump_bytes, MAX_PREAMBLE_STUB_SIZE);
      }
      if (jump_ret == SIDESTEP_JUMP_INSTRUCTION) {
        SIDESTEP_ASSERT(false &&
                        "Found unsupported jump instruction in stub!!");
        return SIDESTEP_UNSUPPORTED_INSTRUCTION;
      }
      target_bytes += jump_bytes;
    } else if (IT_GENERIC == instruction_type) {
      if (IsMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes)) {
        unsigned int mov_bytes = 0;
        if (PatchMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes,
                                     target + target_bytes, &mov_bytes,
                                     MAX_PREAMBLE_STUB_SIZE)
                                     != SIDESTEP_SUCCESS) {
          SIDESTEP_ASSERT(false &&
                          "Found unsupported generic instruction in stub!!");
          return SIDESTEP_UNSUPPORTED_INSTRUCTION;
        }
      } else {
        memcpy(reinterpret_cast(target + target_bytes),
               reinterpret_cast(reinterpret_cast(
                   original_function_stub) + preamble_bytes), cur_bytes);
        target_bytes += cur_bytes;
      }
    } else {
      SIDESTEP_ASSERT(false &&
                      "Found unsupported instruction in stub!!");
      return SIDESTEP_UNSUPPORTED_INSTRUCTION;
    }
    preamble_bytes += cur_bytes;
  }

  FreePreambleBlock(reinterpret_cast(original_function_stub));

  // Restore the protection of the first kRequiredTargetPatchBytes bytes of
  // target to what they were before we started goofing around.
  succeeded = ::VirtualProtect(reinterpret_cast(target),
                               kRequiredTargetPatchBytes,
                               old_target_function_protect,
                               &old_target_function_protect);

  // Flush the instruction cache to make sure the processor doesn't execute the
  // old version of the instructions (before our patch).
  //
  // See comment on FlushInstructionCache elsewhere in this file.
  succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
                                      target,
                                      MAX_PREAMBLE_STUB_SIZE);
  if (!succeeded) {
    SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
    return SIDESTEP_UNEXPECTED;
  }

  SIDESTEP_LOG("PreamblePatcher::Unpatch successfully unpatched.");
  return SIDESTEP_SUCCESS;
}

void PreamblePatcher::Initialize() {
  if (!initialized_) {
    SYSTEM_INFO si = { 0 };
    ::GetSystemInfo(&si);
    granularity_ = si.dwAllocationGranularity;
    pagesize_ = si.dwPageSize;
    initialized_ = true;
  }
}

unsigned char* PreamblePatcher::AllocPreambleBlockNear(void* target) {
  PreamblePage* preamble_page = preamble_pages_;
  while (preamble_page != nullptr) {
    if (preamble_page->free_ != nullptr) {
      __int64 val = reinterpret_cast<__int64>(preamble_page) -
          reinterpret_cast<__int64>(target);
      if ((val > 0 && val + pagesize_ <= INT_MAX) ||
          (val < 0 && val >= INT_MIN)) {
        break;
      }
    }
    preamble_page = preamble_page->next_;
  }

  // The free_ member of the page is used to store the next available block
  // of memory to use or nullptr if there are no chunks available, in which case
  // we'll allocate a new page.
  if (preamble_page == nullptr || preamble_page->free_ == nullptr) {
    // Create a new preamble page and initialize the free list
    preamble_page = reinterpret_cast(AllocPageNear(target));
    SIDESTEP_ASSERT(preamble_page != nullptr && "Could not allocate page!");
    void** pp = &preamble_page->free_;
    unsigned char* ptr = reinterpret_cast(preamble_page) +
        MAX_PREAMBLE_STUB_SIZE;
    unsigned char* limit = reinterpret_cast(preamble_page) +
        pagesize_;
    while (ptr < limit) {
      *pp = ptr;
      pp = reinterpret_cast(ptr);
      ptr += MAX_PREAMBLE_STUB_SIZE;
    }
    *pp = nullptr;
    // Insert the new page into the list
    preamble_page->magic_ = kPreamblePageMagic;
    preamble_page->next_ = preamble_pages_;
    preamble_pages_ = preamble_page;
  }
  unsigned char* ret = reinterpret_cast(preamble_page->free_);
  preamble_page->free_ = *(reinterpret_cast(preamble_page->free_));
  return ret;
}

void PreamblePatcher::FreePreambleBlock(unsigned char* block) {
  SIDESTEP_ASSERT(block != nullptr);
  SIDESTEP_ASSERT(granularity_ != 0);
  uintptr_t ptr = reinterpret_cast(block);
  ptr -= ptr & (granularity_ - 1);
  PreamblePage* preamble_page = reinterpret_cast(ptr);
  SIDESTEP_ASSERT(preamble_page->magic_ == kPreamblePageMagic);
  *(reinterpret_cast(block)) = preamble_page->free_;
  preamble_page->free_ = block;
}

void* PreamblePatcher::AllocPageNear(void* target) {
  MEMORY_BASIC_INFORMATION mbi = { 0 };
  if (!::VirtualQuery(target, &mbi, sizeof(mbi))) {
    SIDESTEP_ASSERT(false && "VirtualQuery failed on target address");
    return 0;
  }
  if (initialized_ == false) {
    PreamblePatcher::Initialize();
    SIDESTEP_ASSERT(initialized_);
  }
  void* pv = nullptr;
  unsigned char* allocation_base = reinterpret_cast(
      mbi.AllocationBase);
  __int64 i = 1;
  bool high_target = reinterpret_cast<__int64>(target) > UINT_MAX;
  while (pv == nullptr) {
    __int64 val = reinterpret_cast<__int64>(allocation_base) -
        (i * granularity_);
    if (high_target &&
        reinterpret_cast<__int64>(target) - val > INT_MAX) {
        // We're further than 2GB from the target
      break;
    } else if (val <= 0) {
      // Less than 0
      break;
    }
    pv = ::VirtualAlloc(reinterpret_cast(allocation_base -
                            (i++ * granularity_)),
                        pagesize_, MEM_COMMIT | MEM_RESERVE,
                        PAGE_EXECUTE_READWRITE);
  }

  // We couldn't allocate low, try to allocate high
  if (pv == nullptr) {
    i = 1;
    // Round up to the next multiple of page granularity
    allocation_base = reinterpret_cast(
        (reinterpret_cast<__int64>(target) &
        (~(granularity_ - 1))) + granularity_);
    while (pv == nullptr) {
      __int64 val = reinterpret_cast<__int64>(allocation_base) +
          (i * granularity_) - reinterpret_cast<__int64>(target);
      if (val > INT_MAX || val < 0) {
        // We're too far or we overflowed
        break;
      }
      pv = ::VirtualAlloc(reinterpret_cast(allocation_base +
                              (i++ * granularity_)),
                          pagesize_, MEM_COMMIT | MEM_RESERVE,
                          PAGE_EXECUTE_READWRITE);
    }
  }
  return pv;
}

bool PreamblePatcher::IsShortConditionalJump(
    unsigned char* target,
    unsigned int instruction_size) {
  return (*(target) & 0x70) == 0x70 && instruction_size == 2;
}

bool PreamblePatcher::IsShortJump(
    unsigned char* target,
    unsigned int instruction_size) {
  return target[0] == 0xeb && instruction_size == 2;
}

bool PreamblePatcher::IsNearConditionalJump(
    unsigned char* target,
    unsigned int instruction_size) {
  return *(target) == 0xf && (*(target + 1) & 0x80) == 0x80 &&
      instruction_size == 6;
}

bool PreamblePatcher::IsNearRelativeJump(
    unsigned char* target,
    unsigned int instruction_size) {
  return *(target) == 0xe9 && instruction_size == 5;
}

bool PreamblePatcher::IsNearAbsoluteCall(
    unsigned char* target,
    unsigned int instruction_size) {
  return *(target) == 0xff && (*(target + 1) & 0x10) == 0x10 &&
      instruction_size == 6;
}

bool PreamblePatcher::IsNearRelativeCall(
    unsigned char* target,
    unsigned int instruction_size) {
  return *(target) == 0xe8 && instruction_size == 5;
}

bool PreamblePatcher::IsMovWithDisplacement(
    unsigned char* target,
    unsigned int instruction_size) {
  // In this case, the ModRM byte's mod field will be 0 and r/m will be 101b (5)
  return instruction_size == 7 && *target == 0x48 && *(target + 1) == 0x8b &&
      (*(target + 2) >> 6) == 0 && (*(target + 2) & 0x7) == 5;
}

SideStepError PreamblePatcher::PatchShortConditionalJump(
    unsigned char* source,
    unsigned int instruction_size,
    unsigned char* target,
    unsigned int* target_bytes,
    unsigned int target_size) {
  // note: rel8 offset is signed. Thus we need to ask for signed char
  // to negative offsets right
  unsigned char* original_jump_dest = (source + 2) + static_cast(source[1]);
  unsigned char* stub_jump_from = target + 6;
  __int64 fixup_jump_offset = original_jump_dest - stub_jump_from;
  if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) {
    SIDESTEP_ASSERT(false &&
                    "Unable to fix up short jump because target"
                    " is too far away.");
    return SIDESTEP_JUMP_INSTRUCTION;
  }

  *target_bytes = 6;
  if (target_size > *target_bytes) {
    // Convert the short jump to a near jump.
    //
    // 0f 8x xx xx xx xx = Jcc rel32off
    unsigned short jmpcode = ((0x80 | (source[0] & 0xf)) << 8) | 0x0f;
    memcpy(reinterpret_cast(target),
           reinterpret_cast(&jmpcode), 2);
    memcpy(reinterpret_cast(target + 2),
           reinterpret_cast(&fixup_jump_offset), 4);
  }

  return SIDESTEP_SUCCESS;
}

SideStepError PreamblePatcher::PatchShortJump(
    unsigned char* source,
    unsigned int instruction_size,
    unsigned char* target,
    unsigned int* target_bytes,
    unsigned int target_size) {
  // note: rel8 offset is _signed_. Thus we need signed char here.
  unsigned char* original_jump_dest = (source + 2) + static_cast(source[1]);
  unsigned char* stub_jump_from = target + 5;
  __int64 fixup_jump_offset = original_jump_dest - stub_jump_from;
  if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) {
    SIDESTEP_ASSERT(false &&
                    "Unable to fix up short jump because target"
                    " is too far away.");
    return SIDESTEP_JUMP_INSTRUCTION;
  }

  *target_bytes = 5;
  if (target_size > *target_bytes) {
    // Convert the short jump to a near jump.
    //
    // e9 xx xx xx xx = jmp rel32off
    target[0] = 0xe9;
    memcpy(reinterpret_cast(target + 1),
           reinterpret_cast(&fixup_jump_offset), 4);
  }

  return SIDESTEP_SUCCESS;
}

SideStepError PreamblePatcher::PatchNearJumpOrCall(
    unsigned char* source,
    unsigned int instruction_size,
    unsigned char* target,
    unsigned int* target_bytes,
    unsigned int target_size) {
  SIDESTEP_ASSERT(instruction_size == 5 || instruction_size == 6);
  unsigned int jmp_offset_in_instruction = instruction_size == 5 ? 1 : 2;
  unsigned char* original_jump_dest = reinterpret_cast(
      reinterpret_cast<__int64>(source + instruction_size) +
      *(reinterpret_cast(source + jmp_offset_in_instruction)));
  unsigned char* stub_jump_from = target + instruction_size;
  __int64 fixup_jump_offset = original_jump_dest - stub_jump_from;
  if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) {
    SIDESTEP_ASSERT(false &&
                    "Unable to fix up near jump because target"
                    " is too far away.");
    return SIDESTEP_JUMP_INSTRUCTION;
  }

  if ((fixup_jump_offset < SCHAR_MAX && fixup_jump_offset > SCHAR_MIN)) {
    *target_bytes = 2;
    if (target_size > *target_bytes) {
      // If the new offset is in range, use a short jump instead of a near jump.
      if (source[0] == ASM_JCC32REL_0 &&
          (source[1] & ASM_JCC32REL_1_MASK) == ASM_JCC32REL_1_MASK) {
        unsigned short jmpcode = (static_cast(
            fixup_jump_offset) << 8) | (0x70 | (source[1] & 0xf));
        memcpy(reinterpret_cast(target),
               reinterpret_cast(&jmpcode),
               2);
      } else {
        target[0] = ASM_JMP8REL;
        target[1] = static_cast(fixup_jump_offset);
      }
    }
  } else {
    *target_bytes = instruction_size;
    if (target_size > *target_bytes) {
      memcpy(reinterpret_cast(target),
             reinterpret_cast(source),
             jmp_offset_in_instruction);
      memcpy(reinterpret_cast(target + jmp_offset_in_instruction),
             reinterpret_cast(&fixup_jump_offset),
             4);
    }
  }

  return SIDESTEP_SUCCESS;
}

SideStepError PreamblePatcher::PatchMovWithDisplacement(
     unsigned char* source,
     unsigned int instruction_size,
     unsigned char* target,
     unsigned int* target_bytes,
     unsigned int target_size) {
  SIDESTEP_ASSERT(instruction_size == 7);
  const int mov_offset_in_instruction = 3; // 0x48 0x8b 0x0d 
  unsigned char* original_mov_dest = reinterpret_cast(
      reinterpret_cast<__int64>(source + instruction_size) +
      *(reinterpret_cast(source + mov_offset_in_instruction)));
  unsigned char* stub_mov_from = target + instruction_size;
  __int64 fixup_mov_offset = original_mov_dest - stub_mov_from;
  if (fixup_mov_offset > INT_MAX || fixup_mov_offset < INT_MIN) {
    SIDESTEP_ASSERT(false &&
        "Unable to fix up near MOV because target is too far away.");
    return SIDESTEP_UNEXPECTED;
  }
  *target_bytes = instruction_size;
  if (target_size > *target_bytes) {
    memcpy(reinterpret_cast(target),
           reinterpret_cast(source),
           mov_offset_in_instruction);
    memcpy(reinterpret_cast(target + mov_offset_in_instruction),
           reinterpret_cast(&fixup_mov_offset),
           4);
  }
  return SIDESTEP_SUCCESS;
}

};  // namespace sidestep
gperftools-gperftools-2.18/src/windows/preamble_patcher.h000066400000000000000000000635411513545575200237660ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 * Author: Scott Francis
 *
 * Definition of PreamblePatcher
 */

#ifndef GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_
#define GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_

#include "config.h"
#include 

// compatibility shim
#include "base/logging.h"
#define SIDESTEP_ASSERT(cond)  RAW_DCHECK(cond, #cond)
#define SIDESTEP_LOG(msg)      RAW_VLOG(1, msg)

// Maximum size of the preamble stub. We overwrite at least the first 5
// bytes of the function. Considering the worst case scenario, we need 4
// bytes + the max instruction size + 5 more bytes for our jump back to
// the original code. With that in mind, 32 is a good number :)
#ifdef _M_X64
// In 64-bit mode we may need more room.  In 64-bit mode all jumps must be
// within +/-2GB of RIP.  Because of this limitation we may need to use a
// trampoline to jump to the replacement function if it is further than 2GB
// away from the target. The trampoline is 14 bytes.
//
// So 4 bytes + max instruction size (17 bytes) + 5 bytes to jump back to the
// original code + trampoline size.  64 bytes is a nice number :-)
#define MAX_PREAMBLE_STUB_SIZE    (64)
#else
#define MAX_PREAMBLE_STUB_SIZE    (32)
#endif

// Determines if this is a 64-bit binary.
#ifdef _M_X64
static const bool kIs64BitBinary = true;
#else
static const bool kIs64BitBinary = false;
#endif

namespace sidestep {

// Possible results of patching/unpatching
enum SideStepError {
  SIDESTEP_SUCCESS = 0,
  SIDESTEP_INVALID_PARAMETER,
  SIDESTEP_INSUFFICIENT_BUFFER,
  SIDESTEP_JUMP_INSTRUCTION,
  SIDESTEP_FUNCTION_TOO_SMALL,
  SIDESTEP_UNSUPPORTED_INSTRUCTION,
  SIDESTEP_NO_SUCH_MODULE,
  SIDESTEP_NO_SUCH_FUNCTION,
  SIDESTEP_ACCESS_DENIED,
  SIDESTEP_UNEXPECTED,
};

#define SIDESTEP_TO_HRESULT(error)                      \
  MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, error)

class DeleteUnsignedCharArray;

// Implements a patching mechanism that overwrites the first few bytes of
// a function preamble with a jump to our hook function, which is then
// able to call the original function via a specially-made preamble-stub
// that imitates the action of the original preamble.
//
// NOTE:  This patching mechanism should currently only be used for
// non-production code, e.g. unit tests, because it is not threadsafe.
// See the TODO in preamble_patcher_with_stub.cc for instructions on what
// we need to do before using it in production code; it's fairly simple
// but unnecessary for now since we only intend to use it in unit tests.
//
// To patch a function, use either of the typesafe Patch() methods.  You
// can unpatch a function using Unpatch().
//
// Typical usage goes something like this:
// @code
// typedef int (*MyTypesafeFuncPtr)(int x);
// MyTypesafeFuncPtr original_func_stub;
// int MyTypesafeFunc(int x) { return x + 1; }
// int HookMyTypesafeFunc(int x) { return 1 + original_func_stub(x); }
//
// void MyPatchInitializingFunction() {
//   original_func_stub = PreamblePatcher::Patch(
//              MyTypesafeFunc, HookMyTypesafeFunc);
//   if (!original_func_stub) {
//     // ... error handling ...
//   }
//
//   // ... continue - you have patched the function successfully ...
// }
// @endcode
//
// Note that there are a number of ways that this method of patching can
// fail.  The most common are:
//    - If there is a jump (jxx) instruction in the first 5 bytes of
//    the function being patched, we cannot patch it because in the
//    current implementation we do not know how to rewrite relative
//    jumps after relocating them to the preamble-stub.  Note that
//    if you really really need to patch a function like this, it
//    would be possible to add this functionality (but at some cost).
//    - If there is a return (ret) instruction in the first 5 bytes
//    we cannot patch the function because it may not be long enough
//    for the jmp instruction we use to inject our patch.
//    - If there is another thread currently executing within the bytes
//    that are copied to the preamble stub, it will crash in an undefined
//    way.
//
// If you get any other error than the above, you're either pointing the
// patcher at an invalid instruction (e.g. into the middle of a multi-
// byte instruction, or not at memory containing executable instructions)
// or, there may be a bug in the disassembler we use to find
// instruction boundaries.
//
// NOTE:  In optimized builds, when you have very trivial functions that
// the compiler can reason do not have side effects, the compiler may
// reuse the result of calling the function with a given parameter, which
// may mean if you patch the function in between your patch will never get
// invoked.  See preamble_patcher_test.cc for an example.
class PERFTOOLS_DLL_DECL PreamblePatcher {
 public:

  // This is a typesafe version of RawPatch(), identical in all other
  // ways than it takes a template parameter indicating the type of the
  // function being patched.
  //
  // @param T The type of the function you are patching. Usually
  // you will establish this type using a typedef, as in the following
  // example:
  // @code
  // typedef BOOL (WINAPI *MessageBoxPtr)(HWND, LPCTSTR, LPCTSTR, UINT);
  // MessageBoxPtr original = nullptr;
  // PreamblePatcher::Patch(MessageBox, Hook_MessageBox, &original);
  // @endcode
  template 
  static SideStepError Patch(T target_function,
                             T replacement_function,
                             T* original_function_stub) {
    // NOTE: casting from a function to a pointer is contra the C++
    //       spec.  It's not safe on IA64, but is on i386.  We use
    //       a C-style cast here to emphasize this is not legal C++.
    return RawPatch((void*)(target_function),
                    (void*)(replacement_function),
                    (void**)(original_function_stub));
  }

  // Patches a named function imported from the named module using
  // preamble patching.  Uses RawPatch() to do the actual patching
  // work.
  //
  // @param T The type of the function you are patching.  Must
  // exactly match the function you specify using module_name and
  // function_name.
  //
  // @param module_name The name of the module from which the function
  // is being imported.  Note that the patch will fail if this module
  // has not already been loaded into the current process.
  //
  // @param function_name The name of the function you wish to patch.
  //
  // @param replacement_function Your replacement function which
  // will be called whenever code tries to call the original function.
  //
  // @param original_function_stub Pointer to memory that should receive a
  // pointer that can be used (e.g. in the replacement function) to call the
  // original function, or nullptr to indicate failure.
  //
  // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS
  // indicates success.
  template 
  static SideStepError Patch(LPCTSTR module_name,
                             LPCSTR function_name,
                             T replacement_function,
                             T* original_function_stub) {
    SIDESTEP_ASSERT(module_name && function_name);
    if (!module_name || !function_name) {
      SIDESTEP_ASSERT(false &&
                      "You must specify a module name and function name.");
      return SIDESTEP_INVALID_PARAMETER;
    }
    HMODULE module = ::GetModuleHandle(module_name);
    SIDESTEP_ASSERT(module != nullptr);
    if (!module) {
      SIDESTEP_ASSERT(false && "Invalid module name.");
      return SIDESTEP_NO_SUCH_MODULE;
    }
    FARPROC existing_function = ::GetProcAddress(module, function_name);
    if (!existing_function) {
      SIDESTEP_ASSERT(
          false && "Did not find any function with that name in the module.");
      return SIDESTEP_NO_SUCH_FUNCTION;
    }
    // NOTE: casting from a function to a pointer is contra the C++
    //       spec.  It's not safe on IA64, but is on i386.  We use
    //       a C-style cast here to emphasize this is not legal C++.
    return RawPatch((void*)existing_function, (void*)replacement_function,
                    (void**)(original_function_stub));
  }

  // Patches a function by overwriting its first few bytes with
  // a jump to a different function.  This is the "worker" function
  // for each of the typesafe Patch() functions.  In most cases,
  // it is preferable to use the Patch() functions rather than
  // this one as they do more checking at compile time.
  //
  // @param target_function A pointer to the function that should be
  // patched.
  //
  // @param replacement_function A pointer to the function that should
  // replace the target function.  The replacement function must have
  // exactly the same calling convention and parameters as the original
  // function.
  //
  // @param original_function_stub Pointer to memory that should receive a
  // pointer that can be used (e.g. in the replacement function) to call the
  // original function, or nullptr to indicate failure.
  //
  // @param original_function_stub Pointer to memory that should receive a
  // pointer that can be used (e.g. in the replacement function) to call the
  // original function, or nullptr to indicate failure.
  //
  // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS
  // indicates success.
  //
  // @note The preamble-stub (the memory pointed to by
  // *original_function_stub) is allocated on the heap, and (in
  // production binaries) never destroyed, resulting in a memory leak.  This
  // will be the case until we implement safe unpatching of a method.
  // However, it is quite difficult to unpatch a method (because other
  // threads in the process may be using it) so we are leaving it for now.
  // See however UnsafeUnpatch, which can be used for binaries where you
  // know only one thread is running, e.g. unit tests.
  static SideStepError RawPatch(void* target_function,
                                void* replacement_function,
                                void** original_function_stub);

  // Unpatches target_function and deletes the stub that previously could be
  // used to call the original version of the function.
  //
  // DELETES the stub that is passed to the function.
  //
  // @param target_function Pointer to the target function which was
  // previously patched, i.e. a pointer which value should match the value
  // of the symbol prior to patching it.
  //
  // @param replacement_function Pointer to the function target_function
  // was patched to.
  //
  // @param original_function_stub Pointer to the stub returned when
  // patching, that could be used to call the original version of the
  // patched function.  This function will also delete the stub, which after
  // unpatching is useless.
  //
  // If your original call was
  //    Patch(VirtualAlloc, MyVirtualAlloc, &origptr)
  // then to undo it you would call
  //    Unpatch(VirtualAlloc, MyVirtualAlloc, origptr);
  //
  // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS
  // indicates success.
  static SideStepError Unpatch(void* target_function,
                               void* replacement_function,
                               void* original_function_stub);

  // A helper routine when patching, which follows jmp instructions at
  // function addresses, to get to the "actual" function contents.
  // This allows us to identify two functions that are at different
  // addresses but actually resolve to the same code.
  //
  // @param target_function Pointer to a function.
  //
  // @return Either target_function (the input parameter), or if
  // target_function's body consists entirely of a JMP instruction,
  // the address it JMPs to (or more precisely, the address at the end
  // of a chain of JMPs).
  template 
  static T ResolveTarget(T target_function) {
    return (T)ResolveTargetImpl((unsigned char*)target_function, nullptr);
  }

  // Allocates a block of memory of size MAX_PREAMBLE_STUB_SIZE that is as
  // close (within 2GB) as possible to target.  This is done to ensure that
  // we can perform a relative jump from target to a trampoline if the
  // replacement function is > +-2GB from target.  This means that we only need
  // to patch 5 bytes in the target function.
  //
  // @param target    Pointer to target function.
  //
  // @return  Returns a block of memory of size MAX_PREAMBLE_STUB_SIZE that can
  //          be used to store a function preamble block.
  static unsigned char* AllocPreambleBlockNear(void* target);

  // Frees a block allocated by AllocPreambleBlockNear.
  //
  // @param block     Block that was returned by AllocPreambleBlockNear.
  static void FreePreambleBlock(unsigned char* block);

 private:
  friend class DeleteUnsignedCharArray;

   // Used to store data allocated for preamble stubs
  struct PreamblePage {
    unsigned int magic_;
    PreamblePage* next_;
    // This member points to a linked list of free blocks within the page
    // or nullptr if at the end
    void* free_;
  };

  // In 64-bit mode, the replacement function must be within 2GB of the original
  // target in order to only require 5 bytes for the function patch.  To meet
  // this requirement we're creating an allocator within this class to
  // allocate blocks that are within 2GB of a given target. This member is the
  // head of a linked list of pages used to allocate blocks that are within
  // 2GB of the target.
  static PreamblePage* preamble_pages_;

  // Page granularity
  static long granularity_;

  // Page size
  static long pagesize_;

  // Determines if the patcher has been initialized.
  static bool initialized_;

  // Used to initialize static members.
  static void Initialize();

  // Patches a function by overwriting its first few bytes with
  // a jump to a different function.  This is similar to the RawPatch
  // function except that it uses the stub allocated by the caller
  // instead of allocating it.
  //
  // We call VirtualProtect to make the
  // target function writable at least for the duration of the call.
  //
  // @param target_function A pointer to the function that should be
  // patched.
  //
  // @param replacement_function A pointer to the function that should
  // replace the target function.  The replacement function must have
  // exactly the same calling convention and parameters as the original
  // function.
  //
  // @param preamble_stub A pointer to a buffer where the preamble stub
  // should be copied. The size of the buffer should be sufficient to
  // hold the preamble bytes.
  //
  // @param stub_size Size in bytes of the buffer allocated for the
  // preamble_stub
  //
  // @param bytes_needed Pointer to a variable that receives the minimum
  // number of bytes required for the stub.  Can be set to nullptr if you're
  // not interested.
  //
  // @return An error code indicating the result of patching.
  static SideStepError RawPatchWithStubAndProtections(
      void* target_function,
      void* replacement_function,
      unsigned char* preamble_stub,
      unsigned long stub_size,
      unsigned long* bytes_needed);

  // A helper function used by RawPatchWithStubAndProtections -- it
  // does everything but the VirtualProtect work.  Defined in
  // preamble_patcher_with_stub.cc.
  //
  // @param target_function A pointer to the function that should be
  // patched.
  //
  // @param replacement_function A pointer to the function that should
  // replace the target function.  The replacement function must have
  // exactly the same calling convention and parameters as the original
  // function.
  //
  // @param preamble_stub A pointer to a buffer where the preamble stub
  // should be copied. The size of the buffer should be sufficient to
  // hold the preamble bytes.
  //
  // @param stub_size Size in bytes of the buffer allocated for the
  // preamble_stub
  //
  // @param bytes_needed Pointer to a variable that receives the minimum
  // number of bytes required for the stub.  Can be set to nullptr if you're
  // not interested.
  //
  // @return An error code indicating the result of patching.
  static SideStepError RawPatchWithStub(void* target_function,
                                        void* replacement_function,
                                        unsigned char* preamble_stub,
                                        unsigned long stub_size,
                                        unsigned long* bytes_needed);


  // A helper routine when patching, which follows jmp instructions at
  // function addresses, to get to the "actual" function contents.
  // This allows us to identify two functions that are at different
  // addresses but actually resolve to the same code.
  //
  // @param target_function Pointer to a function.
  //
  // @param stop_before If, when following JMP instructions from
  // target_function, we get to the address stop, we return
  // immediately, the address that jumps to stop_before.
  //
  // @param stop_before_trampoline  When following JMP instructions from
  // target_function, stop before a trampoline is detected.  See comment in
  // PreamblePatcher::RawPatchWithStub for more information.  This parameter
  // has no effect in 32-bit mode.
  //
  // @return Either target_function (the input parameter), or if
  // target_function's body consists entirely of a JMP instruction,
  // the address it JMPs to (or more precisely, the address at the end
  // of a chain of JMPs).
  static void* ResolveTargetImpl(unsigned char* target_function,
                                 unsigned char* stop_before,
                                 bool stop_before_trampoline = false);

  // Helper routine that attempts to allocate a page as close (within 2GB)
  // as possible to target.
  //
  // @param target    Pointer to target function.
  //
  // @return   Returns an address that is within 2GB of target.
  static void* AllocPageNear(void* target);

  // Helper routine that determines if a target instruction is a short
  // conditional jump.
  //
  // @param target            Pointer to instruction.
  //
  // @param instruction_size  Size of the instruction in bytes.
  //
  // @return  Returns true if the instruction is a short conditional jump.
  static bool IsShortConditionalJump(unsigned char* target,
                                     unsigned int instruction_size);

  static bool IsShortJump(unsigned char *target, unsigned int instruction_size);

  // Helper routine that determines if a target instruction is a near
  // conditional jump.
  //
  // @param target            Pointer to instruction.
  //
  // @param instruction_size  Size of the instruction in bytes.
  //
  // @return  Returns true if the instruction is a near conditional jump.
  static bool IsNearConditionalJump(unsigned char* target,
                                    unsigned int instruction_size);

  // Helper routine that determines if a target instruction is a near
  // relative jump.
  //
  // @param target            Pointer to instruction.
  //
  // @param instruction_size  Size of the instruction in bytes.
  //
  // @return  Returns true if the instruction is a near absolute jump.
  static bool IsNearRelativeJump(unsigned char* target,
                                 unsigned int instruction_size);

  // Helper routine that determines if a target instruction is a near
  // absolute call.
  //
  // @param target            Pointer to instruction.
  //
  // @param instruction_size  Size of the instruction in bytes.
  //
  // @return  Returns true if the instruction is a near absolute call.
  static bool IsNearAbsoluteCall(unsigned char* target,
                                 unsigned int instruction_size);

  // Helper routine that determines if a target instruction is a near
  // absolute call.
  //
  // @param target            Pointer to instruction.
  //
  // @param instruction_size  Size of the instruction in bytes.
  //
  // @return  Returns true if the instruction is a near absolute call.
  static bool IsNearRelativeCall(unsigned char* target,
                                 unsigned int instruction_size);

  // Helper routine that determines if a target instruction is a 64-bit MOV
  // that uses a RIP-relative displacement.
  //
  // @param target            Pointer to instruction.
  //
  // @param instruction_size  Size of the instruction in bytes.
  //
  // @return  Returns true if the instruction is a MOV with displacement.
  static bool IsMovWithDisplacement(unsigned char* target,
                                    unsigned int instruction_size);

  // Helper routine that converts a short conditional jump instruction
  // to a near conditional jump in a target buffer.  Note that the target
  // buffer must be within 2GB of the source for the near jump to work.
  //
  // A short conditional jump instruction is in the format:
  // 7x xx = Jcc rel8off
  //
  // @param source              Pointer to instruction.
  //
  // @param instruction_size    Size of the instruction.
  //
  // @param target              Target buffer to write the new instruction.
  //
  // @param target_bytes        Pointer to a buffer that contains the size
  //                            of the target instruction, in bytes.
  //
  // @param target_size         Size of the target buffer.
  //
  // @return  Returns SIDESTEP_SUCCESS if successful, otherwise an error.
  static SideStepError PatchShortConditionalJump(unsigned char* source,
                                                 unsigned int instruction_size,
                                                 unsigned char* target,
                                                 unsigned int* target_bytes,
                                                 unsigned int target_size);

  static SideStepError PatchShortJump(unsigned char* source,
                                      unsigned int instruction_size,
                                      unsigned char* target,
                                      unsigned int* target_bytes,
                                      unsigned int target_size);

  // Helper routine that converts an instruction that will convert various
  // jump-like instructions to corresponding instructions in the target buffer.
  // What this routine does is fix up the relative offsets contained in jump
  // instructions to point back to the original target routine.  Like with
  // PatchShortConditionalJump, the target buffer must be within 2GB of the
  // source.
  //
  // We currently handle the following instructions:
  //
  // E9 xx xx xx xx     = JMP rel32off
  // 0F 8x xx xx xx xx  = Jcc rel32off
  // FF /2 xx xx xx xx  = CALL reg/mem32/mem64
  // E8 xx xx xx xx     = CALL rel32off
  //
  // It should not be hard to update this function to support other
  // instructions that jump to relative targets.
  //
  // @param source              Pointer to instruction.
  //
  // @param instruction_size    Size of the instruction.
  //
  // @param target              Target buffer to write the new instruction.
  //
  // @param target_bytes        Pointer to a buffer that contains the size
  //                            of the target instruction, in bytes.
  //
  // @param target_size         Size of the target buffer.
  //
  // @return  Returns SIDESTEP_SUCCESS if successful, otherwise an error.
  static SideStepError PatchNearJumpOrCall(unsigned char* source,
                                           unsigned int instruction_size,
                                           unsigned char* target,
                                           unsigned int* target_bytes,
                                           unsigned int target_size);

  // Helper routine that patches a 64-bit MOV instruction with a RIP-relative
  // displacement.  The target buffer must be within 2GB of the source.
  //
  // 48 8B 0D XX XX XX XX = MOV rel32off
  //
  // @param source              Pointer to instruction.
  //
  // @param instruction_size    Size of the instruction.
  //
  // @param target              Target buffer to write the new instruction.
  //
  // @param target_bytes        Pointer to a buffer that contains the size
  //                            of the target instruction, in bytes.
  //
  // @param target_size         Size of the target buffer.
  //
  // @return  Returns SIDESTEP_SUCCESS if successful, otherwise an error.
  static SideStepError PatchMovWithDisplacement(unsigned char* source,
                                                unsigned int instruction_size,
                                                unsigned char* target,
                                                unsigned int* target_bytes,
                                                unsigned int target_size);
};

};  // namespace sidestep

#endif  // GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_
gperftools-gperftools-2.18/src/windows/preamble_patcher_test.cc000066400000000000000000000336251513545575200251630ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2011, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 * Author: Scott Francis
 *
 * Unit tests for PreamblePatcher
 */

#include "config_for_unittests.h"
#include "preamble_patcher.h"
#include "mini_disassembler.h"
#pragma warning(push)
#pragma warning(disable:4553)
#include "auto_testing_hook.h"
#pragma warning(pop)

#define WIN32_LEAN_AND_MEAN
#include 
#include 

// Turning off all optimizations for this file, since the official build's
// "Whole program optimization" seems to cause the TestPatchUsingDynamicStub
// test to crash with an access violation.  We debugged this and found
// that the optimized access a register that is changed by a call to the hook
// function.
#pragma optimize("", off)

// A convenience macro to avoid a lot of casting in the tests.
// I tried to make this a templated function, but windows complained:
//     error C2782: 'sidestep::SideStepError `anonymous-namespace'::Unpatch(T,T,T *)' : template parameter 'T' is ambiguous
//        could be 'int (int)'
//        or       'int (__cdecl *)(int)'
// My life isn't long enough to try to figure out how to fix this.
#define UNPATCH(target_function, replacement_function, original_function_stub) \
  sidestep::PreamblePatcher::Unpatch((void*)(target_function),          \
                                     (void*)(replacement_function),     \
                                     (void*)(original_function))

namespace {

// Function for testing - this is what we patch
//
// NOTE:  Because of the way the compiler optimizes this function in
// release builds, we need to use a different input value every time we
// call it within a function, otherwise the compiler will just reuse the
// last calculated incremented value.
int __declspec(noinline) IncrementNumber(int i) {
#ifdef _M_X64
  __int64 i2 = i + 1;
  return (int) i2;
#else
   return i + 1;
#endif
}

extern "C" int TooShortFunction(int);

extern "C" int JumpShortCondFunction(int);

extern "C" int JumpNearCondFunction(int);

extern "C" int JumpAbsoluteFunction(int);

extern "C" int CallNearRelativeFunction(int);

typedef int (*IncrementingFunc)(int);
IncrementingFunc original_function;

int HookIncrementNumber(int i) {
  SIDESTEP_ASSERT(original_function != nullptr);
  int incremented_once = original_function(i);
  return incremented_once + 1;
}

// For the AutoTestingHook test, we can't use original_function, because
// all that is encapsulated.
// This function "increments" by 10, just to set it apart from the other
// functions.
int __declspec(noinline) AutoHookIncrementNumber(int i) {
  return i + 10;
}

};  // namespace

namespace sidestep {

bool TestDisassembler() {
   unsigned int instruction_size = 0;
   sidestep::MiniDisassembler disassembler;
   void * target = reinterpret_cast(IncrementNumber);
   void * new_target = PreamblePatcher::ResolveTarget(target);
   if (target != new_target)
      target = new_target;

   while (1) {
      sidestep::InstructionType instructionType = disassembler.Disassemble(
         reinterpret_cast(target) + instruction_size,
         instruction_size);
      if (sidestep::IT_RETURN == instructionType) {
         return true;
      }
   }
}

bool TestPatchWithLongJump() {
  original_function = nullptr;
  void *p = ::VirtualAlloc(reinterpret_cast(0x0000020000000000), 4096,
                           MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  SIDESTEP_EXPECT_TRUE(p != nullptr);
  memset(p, 0xcc, 4096);
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       sidestep::PreamblePatcher::Patch(IncrementNumber,
                                                        (IncrementingFunc) p,
                                                        &original_function));
  SIDESTEP_ASSERT((*original_function)(1) == 2);
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       UNPATCH(IncrementNumber,
                               (IncrementingFunc)p,
                               original_function));
  ::VirtualFree(p, 0, MEM_RELEASE);
  return true;
}

bool TestPatchWithPreambleShortCondJump() {
  original_function = nullptr;
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       sidestep::PreamblePatcher::Patch(JumpShortCondFunction,
                                                        HookIncrementNumber,
                                                        &original_function));
  (*original_function)(1);
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       UNPATCH(JumpShortCondFunction,
                               (void*)HookIncrementNumber,
                               original_function));
  return true;
}

bool TestPatchWithPreambleNearRelativeCondJump() {
  original_function = nullptr;
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       sidestep::PreamblePatcher::Patch(JumpNearCondFunction,
                                                        HookIncrementNumber,
                                                        &original_function));
  (*original_function)(0);
  (*original_function)(1);
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       UNPATCH(JumpNearCondFunction,
                               HookIncrementNumber,
                               original_function));
  return true;
}

bool TestPatchWithPreambleAbsoluteJump() {
  original_function = nullptr;
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       sidestep::PreamblePatcher::Patch(JumpAbsoluteFunction,
                                                        HookIncrementNumber,
                                                        &original_function));
  (*original_function)(0);
  (*original_function)(1);
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       UNPATCH(JumpAbsoluteFunction,
                               HookIncrementNumber,
                               original_function));
  return true;
}

bool TestPatchWithPreambleNearRelativeCall() {
  original_function = nullptr;
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       sidestep::PreamblePatcher::Patch(
                                                    CallNearRelativeFunction,
                                                    HookIncrementNumber,
                                                    &original_function));
  (*original_function)(0);
  (*original_function)(1);
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       UNPATCH(CallNearRelativeFunction,
                               HookIncrementNumber,
                               original_function));
  return true;
}

bool TestPatchUsingDynamicStub() {
  original_function = nullptr;
  SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       sidestep::PreamblePatcher::Patch(IncrementNumber,
                                                        HookIncrementNumber,
                                                        &original_function));
  SIDESTEP_EXPECT_TRUE(original_function);
  SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 4);
  SIDESTEP_EXPECT_TRUE(original_function(3) == 4);

  // Clearbox test to see that the function has been patched.
  sidestep::MiniDisassembler disassembler;
  unsigned int instruction_size = 0;
  SIDESTEP_EXPECT_TRUE(sidestep::IT_JUMP == disassembler.Disassemble(
                           reinterpret_cast(IncrementNumber),
                           instruction_size));

  // Since we patched IncrementNumber, its first statement is a
  // jmp to the hook function.  So verify that we now can not patch
  // IncrementNumber because it starts with a jump.
#if 0
  IncrementingFunc dummy = nullptr;
  // TODO(joi@chromium.org): restore this test once flag is added to
  // disable JMP following
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_JUMP_INSTRUCTION ==
                       sidestep::PreamblePatcher::Patch(IncrementNumber,
                                                        HookIncrementNumber,
                                                        &dummy));

  // This test disabled because code in preamble_patcher_with_stub.cc
  // asserts before returning the error code -- so there is no way
  // to get an error code here, in debug build.
  dummy = nullptr;
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_FUNCTION_TOO_SMALL ==
                       sidestep::PreamblePatcher::Patch(TooShortFunction,
                                                        HookIncrementNumber,
                                                        &dummy));
#endif

  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       UNPATCH(IncrementNumber,
                               HookIncrementNumber,
                               original_function));
  return true;
}

bool PatchThenUnpatch() {
  original_function = nullptr;
  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       sidestep::PreamblePatcher::Patch(IncrementNumber,
                                                        HookIncrementNumber,
                                                        &original_function));
  SIDESTEP_EXPECT_TRUE(original_function);
  SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 3);
  SIDESTEP_EXPECT_TRUE(original_function(2) == 3);

  SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
                       UNPATCH(IncrementNumber,
                               HookIncrementNumber,
                               original_function));
  original_function = nullptr;
  SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);

  return true;
}

bool AutoTestingHookTest() {
  SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);

  // Inner scope, so we can test what happens when the AutoTestingHook
  // goes out of scope
  {
    AutoTestingHook hook = MakeTestingHook(IncrementNumber,
                                           AutoHookIncrementNumber);
    (void) hook;
    SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
  }
  SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);

  return true;
}

bool AutoTestingHookInContainerTest() {
  SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);

  // Inner scope, so we can test what happens when the AutoTestingHook
  // goes out of scope
  {
    AutoTestingHookHolder hook(MakeTestingHookHolder(IncrementNumber,
                                                     AutoHookIncrementNumber));
    (void) hook;
    SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
  }
  SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);

  return true;
}

bool TestPreambleAllocation() {
  __int64 diff = 0;
  void* p1 = reinterpret_cast(0x110000000);
  void* p2 = reinterpret_cast(0x810000000);
  unsigned char* b1 = PreamblePatcher::AllocPreambleBlockNear(p1);
  SIDESTEP_EXPECT_TRUE(b1 != nullptr);
  diff = reinterpret_cast<__int64>(p1) - reinterpret_cast<__int64>(b1);
  // Ensure blocks are within 2GB
  SIDESTEP_EXPECT_TRUE(diff <= INT_MAX && diff >= INT_MIN);
  unsigned char* b2 = PreamblePatcher::AllocPreambleBlockNear(p2);
  SIDESTEP_EXPECT_TRUE(b2 != nullptr);
  diff = reinterpret_cast<__int64>(p2) - reinterpret_cast<__int64>(b2);
  SIDESTEP_EXPECT_TRUE(diff <= INT_MAX && diff >= INT_MIN);

  // Ensure we're reusing free blocks
  unsigned char* b3 = b1;
  unsigned char* b4 = b2;
  PreamblePatcher::FreePreambleBlock(b1);
  PreamblePatcher::FreePreambleBlock(b2);
  b1 = PreamblePatcher::AllocPreambleBlockNear(p1);
  SIDESTEP_EXPECT_TRUE(b1 == b3);
  b2 = PreamblePatcher::AllocPreambleBlockNear(p2);
  SIDESTEP_EXPECT_TRUE(b2 == b4);
  PreamblePatcher::FreePreambleBlock(b1);
  PreamblePatcher::FreePreambleBlock(b2);

  return true;
}

bool UnitTests() {
  return TestPatchWithPreambleNearRelativeCall() &&
      TestPatchWithPreambleAbsoluteJump() &&
      TestPatchWithPreambleNearRelativeCondJump() &&
      TestPatchWithPreambleShortCondJump() &&
      TestDisassembler() && TestPatchWithLongJump() &&
      TestPatchUsingDynamicStub() && PatchThenUnpatch() &&
      AutoTestingHookTest() && AutoTestingHookInContainerTest() &&
      TestPreambleAllocation();
}

};  // namespace sidestep

int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
  if (size == 0)        // not even room for a \0?
    return -1;          // not what C99 says to do, but what windows does
  str[size-1] = '\0';
  return _vsnprintf(str, size-1, format, ap);
}

int _tmain(int argc, _TCHAR* argv[])
{
  bool ret = sidestep::UnitTests();
  printf("%s\n", ret ? "PASS" : "FAIL");
  return ret ? 0 : -1;
}

#pragma optimize("", on)
gperftools-gperftools-2.18/src/windows/preamble_patcher_with_stub.cc000066400000000000000000000326311513545575200262100ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * Author: Joi Sigurdsson
 * Author: Scott Francis
 *
 * Implementation of PreamblePatcher
 */

#include "preamble_patcher.h"

#include "mini_disassembler.h"

// Definitions of assembly statements we need
#define ASM_JMP32REL 0xE9
#define ASM_INT3 0xCC
#define ASM_NOP 0x90
// X64 opcodes
#define ASM_MOVRAX_IMM 0xB8
#define ASM_REXW 0x48
#define ASM_JMP 0xFF
#define ASM_JMP_RAX 0xE0
#define ASM_PUSH 0x68
#define ASM_RET 0xC3

namespace sidestep {

SideStepError PreamblePatcher::RawPatchWithStub(
    void* target_function,
    void* replacement_function,
    unsigned char* preamble_stub,
    unsigned long stub_size,
    unsigned long* bytes_needed) {
  if ((nullptr == target_function) ||
      (nullptr == replacement_function) ||
      (nullptr == preamble_stub)) {
    SIDESTEP_ASSERT(false &&
                    "Invalid parameters - either pTargetFunction or "
                    "pReplacementFunction or pPreambleStub were nullptr.");
    return SIDESTEP_INVALID_PARAMETER;
  }

  // TODO(V7:joi) Siggi and I just had a discussion and decided that both
  // patching and unpatching are actually unsafe.  We also discussed a
  // method of making it safe, which is to freeze all other threads in the
  // process, check their thread context to see if their eip is currently
  // inside the block of instructions we need to copy to the stub, and if so
  // wait a bit and try again, then unfreeze all threads once we've patched.
  // Not implementing this for now since we're only using SideStep for unit
  // testing, but if we ever use it for production code this is what we
  // should do.
  //
  // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using
  // FPU instructions, and on newer processors we could use cmpxchg8b or
  // cmpxchg16b. So it might be possible to do the patching/unpatching
  // atomically and avoid having to freeze other threads.  Note though, that
  // doing it atomically does not help if one of the other threads happens
  // to have its eip in the middle of the bytes you change while you change
  // them.
  unsigned char* target = reinterpret_cast(target_function);
  unsigned int required_trampoline_bytes = 0;
  const unsigned int kRequiredStubJumpBytes = 5;
  const unsigned int kRequiredTargetPatchBytes = 5;

  // Initialize the stub with INT3's just in case.
  if (stub_size) {
    memset(preamble_stub, 0xcc, stub_size);
  }
  if (kIs64BitBinary) {
    // In 64-bit mode JMP instructions are always relative to RIP.  If the
    // replacement - target offset is > 2GB, we can't JMP to the replacement
    // function.  In this case, we're going to use a trampoline - that is,
    // we're going to do a relative jump to a small chunk of code in the stub
    // that will then do the absolute jump to the replacement function.  By
    // doing this, we only need to patch 5 bytes in the target function, as
    // opposed to patching 12 bytes if we were to do an absolute jump.
    //
    // Note that the first byte of the trampoline is a NOP instruction.  This
    // is used as a trampoline signature that will be detected when unpatching
    // the function.
    //
    // jmp 
    //
    // trampoline:
    //    nop
    //    mov rax, 
    //    jmp rax
    //
    __int64 replacement_target_offset = reinterpret_cast<__int64>(
        replacement_function) - reinterpret_cast<__int64>(target) - 5;
    if (replacement_target_offset > INT_MAX
        || replacement_target_offset < INT_MIN) {
      // The stub needs to be within 2GB of the target for the trampoline to
      // work!
      __int64 trampoline_offset = reinterpret_cast<__int64>(preamble_stub)
          - reinterpret_cast<__int64>(target) - 5;
      if (trampoline_offset > INT_MAX || trampoline_offset < INT_MIN) {
        // We're screwed.
        SIDESTEP_ASSERT(false
                       && "Preamble stub is too far from target to patch.");
        return SIDESTEP_UNEXPECTED;
      }
      required_trampoline_bytes = 13;
    }
  }

  // skip endbr{32,64} if it is at the
  // target. https://www.felixcloutier.com/x86/endbr32 and
  // https://www.felixcloutier.com/x86/endbr64
  if (target[0] == 0xf3 && target[1] == 0x0f && target[2] == 0x1e && (target[3] == 0xfb || target[3] == 0xfa)) {
    target += 4;
  }

  // Let's disassemble the preamble of the target function to see if we can
  // patch, and to see how much of the preamble we need to take.  We need 5
  // bytes for our jmp instruction, so let's find the minimum number of
  // instructions to get 5 bytes.
  MiniDisassembler disassembler;
  unsigned int preamble_bytes = 0;
  unsigned int stub_bytes = 0;
  while (preamble_bytes < kRequiredTargetPatchBytes) {
    unsigned int cur_bytes = 0;
    InstructionType instruction_type =
        disassembler.Disassemble(target + preamble_bytes, cur_bytes);
    if (IT_JUMP == instruction_type) {
      unsigned int jump_bytes = 0;
      SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION;
      if (IsShortConditionalJump(target + preamble_bytes, cur_bytes)) {
        jump_ret = PatchShortConditionalJump(target + preamble_bytes, cur_bytes,
                                             preamble_stub + stub_bytes,
                                             &jump_bytes,
                                             stub_size - stub_bytes);
      } else if (IsShortJump(target + preamble_bytes, cur_bytes)) {
        jump_ret = PatchShortJump(target + preamble_bytes, cur_bytes,
                                  preamble_stub + stub_bytes,
                                  &jump_bytes,
                                  stub_size - stub_bytes);
      } else if (IsNearConditionalJump(target + preamble_bytes, cur_bytes) ||
                 IsNearRelativeJump(target + preamble_bytes, cur_bytes) ||
                 IsNearAbsoluteCall(target + preamble_bytes, cur_bytes) ||
                 IsNearRelativeCall(target + preamble_bytes, cur_bytes)) {
         jump_ret = PatchNearJumpOrCall(target + preamble_bytes, cur_bytes,
                                        preamble_stub + stub_bytes, &jump_bytes,
                                        stub_size - stub_bytes);
      }
      if (jump_ret != SIDESTEP_SUCCESS) {
        SIDESTEP_ASSERT(false &&
                        "Unable to patch because there is an unhandled branch "
                        "instruction in the initial preamble bytes.");
        return SIDESTEP_JUMP_INSTRUCTION;
      }
      stub_bytes += jump_bytes;
    } else if (IT_RETURN == instruction_type) {
      SIDESTEP_ASSERT(false &&
                      "Unable to patch because function is too short");
      return SIDESTEP_FUNCTION_TOO_SMALL;
    } else if (IT_GENERIC == instruction_type) {
      if (IsMovWithDisplacement(target + preamble_bytes, cur_bytes)) {
        unsigned int mov_bytes = 0;
        if (PatchMovWithDisplacement(target + preamble_bytes, cur_bytes,
                                     preamble_stub + stub_bytes, &mov_bytes,
                                     stub_size - stub_bytes)
            != SIDESTEP_SUCCESS) {
          return SIDESTEP_UNSUPPORTED_INSTRUCTION;
        }
        stub_bytes += mov_bytes;
      } else {
        memcpy(reinterpret_cast(preamble_stub + stub_bytes),
               reinterpret_cast(target + preamble_bytes), cur_bytes);
        stub_bytes += cur_bytes;
      }
    } else {
      SIDESTEP_ASSERT(false &&
                      "Disassembler encountered unsupported instruction "
                      "(either unused or unknown");
      return SIDESTEP_UNSUPPORTED_INSTRUCTION;
    }
    preamble_bytes += cur_bytes;
  }

  if (nullptr != bytes_needed)
    *bytes_needed = stub_bytes + kRequiredStubJumpBytes
        + required_trampoline_bytes;

  // Inv: cbPreamble is the number of bytes (at least 5) that we need to take
  // from the preamble to have whole instructions that are 5 bytes or more
  // in size total. The size of the stub required is cbPreamble +
  // kRequiredStubJumpBytes (5) + required_trampoline_bytes (0 or 13)
  if (stub_bytes + kRequiredStubJumpBytes + required_trampoline_bytes
      > stub_size) {
    SIDESTEP_ASSERT(false);
    return SIDESTEP_INSUFFICIENT_BUFFER;
  }

  // Now, make a jmp instruction to the rest of the target function (minus the
  // preamble bytes we moved into the stub) and copy it into our preamble-stub.
  // find address to jump to, relative to next address after jmp instruction
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4244)
#endif
  int relative_offset_to_target_rest
      = ((reinterpret_cast(target) + preamble_bytes) -
         (preamble_stub + stub_bytes + kRequiredStubJumpBytes));
#ifdef _MSC_VER
#pragma warning(pop)
#endif
  // jmp (Jump near, relative, displacement relative to next instruction)
  preamble_stub[stub_bytes] = ASM_JMP32REL;
  // copy the address
  memcpy(reinterpret_cast(preamble_stub + stub_bytes + 1),
         reinterpret_cast(&relative_offset_to_target_rest), 4);

  if (kIs64BitBinary && required_trampoline_bytes != 0) {
    // Construct the trampoline
    unsigned int trampoline_pos = stub_bytes + kRequiredStubJumpBytes;
    preamble_stub[trampoline_pos] = ASM_NOP;
    preamble_stub[trampoline_pos + 1] = ASM_REXW;
    preamble_stub[trampoline_pos + 2] = ASM_MOVRAX_IMM;
    memcpy(reinterpret_cast(preamble_stub + trampoline_pos + 3),
           reinterpret_cast(&replacement_function),
           sizeof(void *));
    preamble_stub[trampoline_pos + 11] = ASM_JMP;
    preamble_stub[trampoline_pos + 12] = ASM_JMP_RAX;

    // Now update replacement_function to point to the trampoline
    replacement_function = preamble_stub + trampoline_pos;
  }

  // Inv: preamble_stub points to assembly code that will execute the
  // original function by first executing the first cbPreamble bytes of the
  // preamble, then jumping to the rest of the function.

  // Overwrite the first 5 bytes of the target function with a jump to our
  // replacement function.
  // (Jump near, relative, displacement relative to next instruction)
  target[0] = ASM_JMP32REL;

  // Find offset from instruction after jmp, to the replacement function.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4244)
#endif
  int offset_to_replacement_function =
      reinterpret_cast(replacement_function) -
      reinterpret_cast(target) - 5;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
  // complete the jmp instruction
  memcpy(reinterpret_cast(target + 1),
         reinterpret_cast(&offset_to_replacement_function), 4);

  // Set any remaining bytes that were moved to the preamble-stub to INT3 so
  // as not to cause confusion (otherwise you might see some strange
  // instructions if you look at the disassembly, or even invalid
  // instructions). Also, by doing this, we will break into the debugger if
  // some code calls into this portion of the code.  If this happens, it
  // means that this function cannot be patched using this patcher without
  // further thought.
  if (preamble_bytes > kRequiredTargetPatchBytes) {
    memset(reinterpret_cast(target + kRequiredTargetPatchBytes),
           ASM_INT3, preamble_bytes - kRequiredTargetPatchBytes);
  }

  // Inv: The memory pointed to by target_function now points to a relative
  // jump instruction that jumps over to the preamble_stub.  The preamble
  // stub contains the first stub_size bytes of the original target
  // function's preamble code, followed by a relative jump back to the next
  // instruction after the first cbPreamble bytes.
  //
  // In 64-bit mode the memory pointed to by target_function *may* point to a
  // relative jump instruction that jumps to a trampoline which will then
  // perform an absolute jump to the replacement function.  The preamble stub
  // still contains the original target function's preamble code, followed by a
  // jump back to the instructions after the first preamble bytes.
  //
  return SIDESTEP_SUCCESS;
}

};  // namespace sidestep
gperftools-gperftools-2.18/src/windows/shortproc.asm000066400000000000000000000072261513545575200230430ustar00rootroot00000000000000; Copyright (c) 2011, Google Inc.
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are
; met:
;
;     * Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
;     * Redistributions in binary form must reproduce the above
; copyright notice, this list of conditions and the following disclaimer
; in the documentation and/or other materials provided with the
; distribution.
;     * Neither the name of Google Inc. nor the names of its
; contributors may be used to endorse or promote products derived from
; this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;
; ---
; Author: Scott Francis
;
; Unit tests for PreamblePatcher

IFNDEF AMD64
.MODEL small
ENDIF

.CODE

TooShortFunction PROC
	ret
TooShortFunction ENDP

JumpShortCondFunction PROC
	test cl, 1
	jnz jumpspot
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
	int 3
jumpspot:
	nop
	nop
	nop
	nop
	mov eax, 1
	ret
JumpShortCondFunction ENDP

JumpNearCondFunction PROC
	test cl, 1
	jnz jumpspot
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
jumpspot:
	nop
	nop
	mov eax, 1
	ret
JumpNearCondFunction ENDP

JumpAbsoluteFunction PROC
	test cl, 1
	jmp jumpspot
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
jumpspot:
	nop
	nop
	mov eax, 1
	ret
JumpAbsoluteFunction ENDP

CallNearRelativeFunction PROC
	test cl, 1
	call TooShortFunction
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	mov edx, 0ffff1111H
	nop
	nop
	nop
	ret
CallNearRelativeFunction ENDP

END
gperftools-gperftools-2.18/src/windows/system-alloc.cc000066400000000000000000000157221513545575200232410ustar00rootroot00000000000000// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2013, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// ---
// Author: Petr Hosek

#ifndef _WIN32
# error You should only be including windows/system-alloc.cc in a windows environment!
#endif

#include 
#include 
#include  // std::min
#include 
#include "base/logging.h"
#include "base/spinlock.h"
#include "internal_logging.h"
#include "system-alloc.h"

static SpinLock spinlock;

// The current system allocator declaration
SysAllocator* tcmalloc_sys_alloc;
// Number of bytes taken from system.
size_t TCMalloc_SystemTaken;

class VirtualSysAllocator : public SysAllocator {
public:
  VirtualSysAllocator() : SysAllocator() {
  }
  void* Alloc(size_t size, size_t *actual_size, size_t alignment);
};
static tcmalloc::StaticStorage virtual_space;

// This is mostly like MmapSysAllocator::Alloc, except it does these weird
// munmap's in the middle of the page, which is forbidden in windows.
void* VirtualSysAllocator::Alloc(size_t size, size_t *actual_size,
                                 size_t alignment) {
  // Align on the pagesize boundary
  const int pagesize = getpagesize();
  if (alignment < pagesize) alignment = pagesize;
  size = ((size + alignment - 1) / alignment) * alignment;

  // Report the total number of bytes the OS actually delivered.  This might be
  // greater than |size| because of alignment concerns.  The full size is
  // necessary so that adjacent spans can be coalesced.
  // TODO(antonm): proper processing of alignments
  // in actual_size and decommitting.
  if (actual_size) {
    *actual_size = size;
  }

  // We currently do not support alignments larger than the pagesize or
  // alignments that are not multiples of the pagesize after being floored.
  // If this ability is needed it can be done by the caller (assuming it knows
  // the page size).
  assert(alignment <= pagesize);

  void* result = VirtualAlloc(0, size,
                              MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
  if (result == nullptr)
    return nullptr;

  // If the result is not aligned memory fragmentation will result which can
  // lead to pathological memory use.
  assert((reinterpret_cast(result) & (alignment - 1)) == 0);

  return result;
}

#ifdef _MSC_VER

extern "C" SysAllocator* tc_get_sysalloc_override(SysAllocator *def);
extern "C" SysAllocator* tc_get_sysalloc_default(SysAllocator *def)
{
  return def;
}

#if defined(_M_IX86)
#pragma comment(linker, "/alternatename:_tc_get_sysalloc_override=_tc_get_sysalloc_default")
#elif defined(_M_X64)
#pragma comment(linker, "/alternatename:tc_get_sysalloc_override=tc_get_sysalloc_default")
#endif

#else // !_MSC_VER

extern "C" ATTRIBUTE_NOINLINE
SysAllocator* tc_get_sysalloc_override(SysAllocator *def)
{
  return def;
}

#endif

static bool system_alloc_inited = false;
void InitSystemAllocators(void) {
  VirtualSysAllocator *alloc = virtual_space.Construct();
  tcmalloc_sys_alloc = tc_get_sysalloc_override(alloc);
}

extern PERFTOOLS_DLL_DECL
void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
			   size_t alignment) {
  SpinLockHolder lock_holder(&spinlock);

  if (!system_alloc_inited) {
    InitSystemAllocators();
    system_alloc_inited = true;
  }

  void* result = tcmalloc_sys_alloc->Alloc(size, actual_size, alignment);
  if (result != nullptr) {
    if (actual_size) {
      TCMalloc_SystemTaken += *actual_size;
    } else {
      TCMalloc_SystemTaken += size;
    }
  }
  return result;
}

extern PERFTOOLS_DLL_DECL
bool TCMalloc_SystemRelease(void* start, size_t length) {
  if (VirtualFree(start, length, MEM_DECOMMIT))
    return true;

  // The decommit may fail if the memory region consists of allocations
  // from more than one call to VirtualAlloc.  In this case, fall back to
  // using VirtualQuery to retrieve the allocation boundaries and decommit
  // them each individually.

  char* ptr = static_cast(start);
  char* end = ptr + length;
  MEMORY_BASIC_INFORMATION info;
  while (ptr < end) {
    size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
    assert(resultSize == sizeof(info));
    size_t decommitSize = std::min(info.RegionSize, end - ptr);
    BOOL success = VirtualFree(ptr, decommitSize, MEM_DECOMMIT);
    assert(success == TRUE);
    ptr += decommitSize;
  }

  return true;
}

extern PERFTOOLS_DLL_DECL
void TCMalloc_SystemCommit(void* start, size_t length) {
  if (VirtualAlloc(start, length, MEM_COMMIT, PAGE_READWRITE) == start)
    return;

  // The commit may fail if the memory region consists of allocations
  // from more than one call to VirtualAlloc.  In this case, fall back to
  // using VirtualQuery to retrieve the allocation boundaries and commit them
  // each individually.

  char* ptr = static_cast(start);
  char* end = ptr + length;
  MEMORY_BASIC_INFORMATION info;
  while (ptr < end) {
    size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
    assert(resultSize == sizeof(info));

    size_t commitSize = std::min(info.RegionSize, end - ptr);
    void* newAddress = VirtualAlloc(ptr, commitSize, MEM_COMMIT,
                                    PAGE_READWRITE);
    assert(newAddress == ptr);
    ptr += commitSize;
  }
}

bool RegisterSystemAllocator(SysAllocator *allocator, int priority) {
  return false;   // we don't allow registration on windows, right now
}

void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
  // We don't dump stats on windows, right now
}

SpinLock* GetSysAllocLock() { return &spinlock; }
gperftools-gperftools-2.18/vendor/000077500000000000000000000000001513545575200173235ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/README.vendor000066400000000000000000000025651513545575200215070ustar00rootroot00000000000000
== googletest

googletest is vendored at release-1.8.0-3576-ga05c0915. It was copied
verbatim via git archive and added here.

== libbacktrace

libbacktrace was vendored from github.com/ianlancetaylor/libbacktrace
at commit 793921876c981ce49759114d7bb89bb89b2d3a2d. We dont use its
autotools build infrastructure and integrate it ourselves with mostly
hardcoded config.h and our own Makefile.am bits. Those integration
bits are in libbacktrace-integration in this subdirectory. Main
motivation for such approach is that:

*) we only need symbolization subset

*) we want to avoid polluting global namespace of symbols. We arrange
 for all backtrace symbols to be prefixed tcmalloc_. See
 libbacktrace-integration/config.h.

When updating libbacktrace check that all symbols are renamed by
something like this:

$ make libbacktrace.la
$ objdump -t .libs/libbacktrace.a | grep ' g '

Another notable thing is, we don't bother with mmap support for
reading files metadata and debug info. We actually go to extra length
to replace their alloc.c functions with our own. Our replacement
improves performance some, but most notably it allows us to discard
all the state allocated by libbacktrace. This enables us to not worry
about any synchronization concerns or libbacktrace's lack of ability
to "see" freshly dlopened modules if we did recommended path of doing
thread-ful singleton backtrace state.
gperftools-gperftools-2.18/vendor/googletest/000077500000000000000000000000001513545575200214775ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/.clang-format000066400000000000000000000001641513545575200240530ustar00rootroot00000000000000# Run manually to reformat a file:
# clang-format -i --style=file 
Language:        Cpp
BasedOnStyle:  Google
gperftools-gperftools-2.18/vendor/googletest/.github/000077500000000000000000000000001513545575200230375ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/.github/ISSUE_TEMPLATE/000077500000000000000000000000001513545575200252225ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/.github/ISSUE_TEMPLATE/00-bug_report.yml000066400000000000000000000040201513545575200303260ustar00rootroot00000000000000name: Bug Report
description: Let us know that something does not work as expected.
title: "[Bug]: Please title this bug report"
body:
  - type: textarea
    id: what-happened
    attributes:
      label: Describe the issue
      description: What happened, and what did you expect to happen?
    validations:
      required: true
  - type: textarea
    id: steps
    attributes:
      label: Steps to reproduce the problem
      description: It is important that we are able to reproduce the problem that you are experiencing. Please provide all code and relevant steps to reproduce the problem, including your `BUILD`/`CMakeLists.txt` file and build commands. Links to a GitHub branch or [godbolt.org](https://godbolt.org/) that demonstrate the problem are also helpful.
    validations:
      required: true
  - type: textarea
    id: version
    attributes:
      label: What version of GoogleTest are you using?
      description: Please include the output of `git rev-parse HEAD` or the GoogleTest release version number that you are using.
    validations:
      required: true
  - type: textarea
    id: os
    attributes:
      label: What operating system and version are you using?
      description: If you are using a Linux distribution please include the name and version of the distribution as well.
    validations:
      required: true
  - type: textarea
    id: compiler
    attributes:
      label: What compiler and version are you using?
      description: Please include the output of `gcc -v` or `clang -v`, or the equivalent for your compiler.
    validations:
      required: true
  - type: textarea
    id: buildsystem
    attributes:
      label: What build system are you using?
      description: Please include the output of `bazel --version` or `cmake --version`, or the equivalent for your build system.
    validations:
      required: true
  - type: textarea
    id: additional
    attributes:
      label: Additional context
      description: Add any other context about the problem here.
    validations:
      required: false
gperftools-gperftools-2.18/vendor/googletest/.github/ISSUE_TEMPLATE/10-feature_request.yml000066400000000000000000000020421513545575200313640ustar00rootroot00000000000000name: Feature request
description: Propose a new feature.
title: "[FR]: Please title this feature request"
labels: "enhancement"
body:
  - type: textarea
    id: version
    attributes:
      label: Does the feature exist in the most recent commit?
      description: We recommend using the latest commit from GitHub in your projects.
    validations:
      required: true
  - type: textarea
    id: why
    attributes:
      label: Why do we need this feature?
      description: Ideally, explain why a combination of existing features cannot be used instead.
    validations:
      required: true
  - type: textarea
    id: proposal
    attributes:
      label: Describe the proposal.
      description: Include a detailed description of the feature, with usage examples.
    validations:
      required: true
  - type: textarea
    id: platform
    attributes:
      label: Is the feature specific to an operating system, compiler, or build system version?
      description: If it is, please specify which versions.
    validations:
      required: true
gperftools-gperftools-2.18/vendor/googletest/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000002571513545575200272160ustar00rootroot00000000000000blank_issues_enabled: false
contact_links:
    - name: Get Help
      url: https://github.com/google/googletest/discussions
      about: Please ask and answer questions here.
gperftools-gperftools-2.18/vendor/googletest/.gitignore000066400000000000000000000031271513545575200234720ustar00rootroot00000000000000# Ignore CI build directory
build/
xcuserdata
cmake-build-debug/
.idea/
bazel-bin
bazel-genfiles
bazel-googletest
bazel-out
bazel-testlogs
MODULE.bazel.lock
# python
*.pyc

# Visual Studio files
.vs
*.sdf
*.opensdf
*.VC.opendb
*.suo
*.user
_ReSharper.Caches/
Win32-Debug/
Win32-Release/
x64-Debug/
x64-Release/

# VSCode files
.cache/
cmake-variants.yaml

# Ignore autoconf / automake files
Makefile.in
aclocal.m4
configure
build-aux/
autom4te.cache/
googletest/m4/libtool.m4
googletest/m4/ltoptions.m4
googletest/m4/ltsugar.m4
googletest/m4/ltversion.m4
googletest/m4/lt~obsolete.m4
googlemock/m4

# Ignore generated directories.
googlemock/fused-src/
googletest/fused-src/

# macOS files
.DS_Store
googletest/.DS_Store
googletest/xcode/.DS_Store

# Ignore cmake generated directories and files.
CMakeFiles
CTestTestfile.cmake
Makefile
cmake_install.cmake
googlemock/CMakeFiles
googlemock/CTestTestfile.cmake
googlemock/Makefile
googlemock/cmake_install.cmake
googlemock/gtest
/bin
/googlemock/gmock.dir
/googlemock/gmock_main.dir
/googlemock/RUN_TESTS.vcxproj.filters
/googlemock/RUN_TESTS.vcxproj
/googlemock/INSTALL.vcxproj.filters
/googlemock/INSTALL.vcxproj
/googlemock/gmock_main.vcxproj.filters
/googlemock/gmock_main.vcxproj
/googlemock/gmock.vcxproj.filters
/googlemock/gmock.vcxproj
/googlemock/gmock.sln
/googlemock/ALL_BUILD.vcxproj.filters
/googlemock/ALL_BUILD.vcxproj
/lib
/Win32
/ZERO_CHECK.vcxproj.filters
/ZERO_CHECK.vcxproj
/RUN_TESTS.vcxproj.filters
/RUN_TESTS.vcxproj
/INSTALL.vcxproj.filters
/INSTALL.vcxproj
/googletest-distribution.sln
/CMakeCache.txt
/ALL_BUILD.vcxproj.filters
/ALL_BUILD.vcxproj
gperftools-gperftools-2.18/vendor/googletest/BUILD.bazel000066400000000000000000000163551513545575200233670ustar00rootroot00000000000000# Copyright 2017 Google Inc.
# All Rights Reserved.
#
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#   Bazel Build for Google C++ Testing Framework(Google Test)

package(default_visibility = ["//visibility:public"])

licenses(["notice"])

exports_files(["LICENSE"])

config_setting(
    name = "qnx",
    constraint_values = ["@platforms//os:qnx"],
)

config_setting(
    name = "windows",
    constraint_values = ["@platforms//os:windows"],
)

config_setting(
    name = "freebsd",
    constraint_values = ["@platforms//os:freebsd"],
)

config_setting(
    name = "openbsd",
    constraint_values = ["@platforms//os:openbsd"],
)

# NOTE: Fuchsia is not an officially supported platform.
config_setting(
    name = "fuchsia",
    constraint_values = ["@platforms//os:fuchsia"],
)

config_setting(
    name = "msvc_compiler",
    flag_values = {
        "@bazel_tools//tools/cpp:compiler": "msvc-cl",
    },
    visibility = [":__subpackages__"],
)

config_setting(
    name = "has_absl",
    values = {"define": "absl=1"},
)

# Library that defines the FRIEND_TEST macro.
cc_library(
    name = "gtest_prod",
    hdrs = ["googletest/include/gtest/gtest_prod.h"],
    includes = ["googletest/include"],
)

# Google Test including Google Mock

# For an actual test, use `gtest` and also `gtest_main` if you depend on gtest's
# main(). For a library, use `gtest_for_library` instead if the library can be
# testonly.
cc_library(
    name = "gtest",
    srcs = glob(
        include = [
            "googletest/src/*.cc",
            "googletest/src/*.h",
            "googletest/include/gtest/**/*.h",
            "googlemock/src/*.cc",
            "googlemock/include/gmock/**/*.h",
        ],
        exclude = [
            "googletest/src/gtest-all.cc",
            "googletest/src/gtest_main.cc",
            "googlemock/src/gmock-all.cc",
            "googlemock/src/gmock_main.cc",
        ],
    ),
    hdrs = glob([
        "googletest/include/gtest/*.h",
        "googlemock/include/gmock/*.h",
    ]),
    copts = select({
        ":qnx": [],
        ":windows": [],
        "//conditions:default": ["-pthread"],
    }),
    defines = select({
        ":has_absl": ["GTEST_HAS_ABSL=1"],
        "//conditions:default": [],
    }),
    features = select({
        ":windows": ["windows_export_all_symbols"],
        "//conditions:default": [],
    }),
    includes = [
        "googlemock",
        "googlemock/include",
        "googletest",
        "googletest/include",
    ],
    linkopts = select({
        ":qnx": ["-lregex"],
        ":windows": [],
        ":freebsd": [
            "-lm",
            "-pthread",
        ],
        ":openbsd": [
            "-lm",
            "-pthread",
        ],
        "//conditions:default": ["-pthread"],
    }),
    deps = select({
        ":has_absl": [
            "@abseil-cpp//absl/container:flat_hash_set",
            "@abseil-cpp//absl/debugging:failure_signal_handler",
            "@abseil-cpp//absl/debugging:stacktrace",
            "@abseil-cpp//absl/debugging:symbolize",
            "@abseil-cpp//absl/flags:flag",
            "@abseil-cpp//absl/flags:parse",
            "@abseil-cpp//absl/flags:reflection",
            "@abseil-cpp//absl/flags:usage",
            "@abseil-cpp//absl/strings",
            "@re2",
        ],
        "//conditions:default": [],
    }) + select({
        # `gtest-death-test.cc` has `EXPECT_DEATH` that spawns a process,
        # expects it to crash and inspects its logs with the given matcher,
        # so that's why these libraries are needed.
        # Otherwise, builds targeting Fuchsia would fail to compile.
        ":fuchsia": [
            "@fuchsia_sdk//pkg/fdio",
            "@fuchsia_sdk//pkg/syslog",
            "@fuchsia_sdk//pkg/zx",
        ],
        "//conditions:default": [],
    }),
)

# `gtest`, but testonly. See guidance on `gtest` for when to use this.
alias(
    name = "gtest_for_library",
    testonly = True,
    actual = ":gtest",
)

# Implements main() for tests using gtest. Prefer to depend on `gtest` as well
# to ensure compliance with the layering_check Bazel feature where only the
# direct hdrs values are available.
cc_library(
    name = "gtest_main",
    srcs = ["googlemock/src/gmock_main.cc"],
    features = select({
        ":windows": ["windows_export_all_symbols"],
        "//conditions:default": [],
    }),
    deps = [":gtest"],
)

# The following rules build samples of how to use gTest.
cc_library(
    name = "gtest_sample_lib",
    srcs = [
        "googletest/samples/sample1.cc",
        "googletest/samples/sample2.cc",
        "googletest/samples/sample4.cc",
    ],
    hdrs = [
        "googletest/samples/prime_tables.h",
        "googletest/samples/sample1.h",
        "googletest/samples/sample2.h",
        "googletest/samples/sample3-inl.h",
        "googletest/samples/sample4.h",
    ],
    features = select({
        ":windows": ["windows_export_all_symbols"],
        "//conditions:default": [],
    }),
)

cc_test(
    name = "gtest_samples",
    size = "small",
    # All Samples except:
    #   sample9 (main)
    #   sample10 (main and takes a command line option and needs to be separate)
    srcs = [
        "googletest/samples/sample1_unittest.cc",
        "googletest/samples/sample2_unittest.cc",
        "googletest/samples/sample3_unittest.cc",
        "googletest/samples/sample4_unittest.cc",
        "googletest/samples/sample5_unittest.cc",
        "googletest/samples/sample6_unittest.cc",
        "googletest/samples/sample7_unittest.cc",
        "googletest/samples/sample8_unittest.cc",
    ],
    linkstatic = 0,
    deps = [
        "gtest_sample_lib",
        ":gtest_main",
    ],
)

cc_test(
    name = "sample9_unittest",
    size = "small",
    srcs = ["googletest/samples/sample9_unittest.cc"],
    deps = [":gtest"],
)

cc_test(
    name = "sample10_unittest",
    size = "small",
    srcs = ["googletest/samples/sample10_unittest.cc"],
    deps = [":gtest"],
)
gperftools-gperftools-2.18/vendor/googletest/CMakeLists.txt000066400000000000000000000017321513545575200242420ustar00rootroot00000000000000# Note: CMake support is community-based. The maintainers do not use CMake
# internally.

cmake_minimum_required(VERSION 3.16)

project(googletest-distribution)
set(GOOGLETEST_VERSION 1.16.0)

if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX)
  set(CMAKE_CXX_EXTENSIONS OFF)
endif()

enable_testing()

include(CMakeDependentOption)
include(GNUInstallDirs)

# Note that googlemock target already builds googletest.
option(BUILD_GMOCK "Builds the googlemock subproject" ON)
option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" ON)
option(GTEST_HAS_ABSL "Use Abseil and RE2. Requires Abseil and RE2 to be separately added to the build." OFF)

if(GTEST_HAS_ABSL)
  if(NOT TARGET absl::base)
    find_package(absl REQUIRED)
  endif()
  if(NOT TARGET re2::re2)
    find_package(re2 REQUIRED)
  endif()
endif()

if(BUILD_GMOCK)
  add_subdirectory( googlemock )
else()
  add_subdirectory( googletest )
endif()
gperftools-gperftools-2.18/vendor/googletest/CONTRIBUTING.md000066400000000000000000000130721513545575200237330ustar00rootroot00000000000000# How to become a contributor and submit your own code

## Contributor License Agreements

We'd love to accept your patches! Before we can take them, we have to jump a
couple of legal hurdles.

Please fill out either the individual or corporate Contributor License Agreement
(CLA).

*   If you are an individual writing original source code and you're sure you
    own the intellectual property, then you'll need to sign an
    [individual CLA](https://developers.google.com/open-source/cla/individual).
*   If you work for a company that wants to allow you to contribute your work,
    then you'll need to sign a
    [corporate CLA](https://developers.google.com/open-source/cla/corporate).

Follow either of the two links above to access the appropriate CLA and
instructions for how to sign and return it. Once we receive it, we'll be able to
accept your pull requests.

## Are you a Googler?

If you are a Googler, please make an attempt to submit an internal contribution
rather than a GitHub Pull Request. If you are not able to submit internally, a
PR is acceptable as an alternative.

## Contributing A Patch

1.  Submit an issue describing your proposed change to the
    [issue tracker](https://github.com/google/googletest/issues).
2.  Please don't mix more than one logical change per submittal, because it
    makes the history hard to follow. If you want to make a change that doesn't
    have a corresponding issue in the issue tracker, please create one.
3.  Also, coordinate with team members that are listed on the issue in question.
    This ensures that work isn't being duplicated and communicating your plan
    early also generally leads to better patches.
4.  If your proposed change is accepted, and you haven't already done so, sign a
    Contributor License Agreement
    ([see details above](#contributor-license-agreements)).
5.  Fork the desired repo, develop and test your code changes.
6.  Ensure that your code adheres to the existing style in the sample to which
    you are contributing.
7.  Ensure that your code has an appropriate set of unit tests which all pass.
8.  Submit a pull request.

## The Google Test and Google Mock Communities

The Google Test community exists primarily through the
[discussion group](https://groups.google.com/group/googletestframework) and the
GitHub repository. Likewise, the Google Mock community exists primarily through
their own [discussion group](https://groups.google.com/group/googlemock). You
are definitely encouraged to contribute to the discussion and you can also help
us to keep the effectiveness of the group high by following and promoting the
guidelines listed here.

### Please Be Friendly

Showing courtesy and respect to others is a vital part of the Google culture,
and we strongly encourage everyone participating in Google Test development to
join us in accepting nothing less. Of course, being courteous is not the same as
failing to constructively disagree with each other, but it does mean that we
should be respectful of each other when enumerating the 42 technical reasons
that a particular proposal may not be the best choice. There's never a reason to
be antagonistic or dismissive toward anyone who is sincerely trying to
contribute to a discussion.

Sure, C++ testing is serious business and all that, but it's also a lot of fun.
Let's keep it that way. Let's strive to be one of the friendliest communities in
all of open source.

As always, discuss Google Test in the official GoogleTest discussion group. You
don't have to actually submit code in order to sign up. Your participation
itself is a valuable contribution.

## Style

To keep the source consistent, readable, diffable and easy to merge, we use a
fairly rigid coding style, as defined by the
[google-styleguide](https://github.com/google/styleguide) project. All patches
will be expected to conform to the style outlined
[here](https://google.github.io/styleguide/cppguide.html). Use
[.clang-format](https://github.com/google/googletest/blob/main/.clang-format) to
check your formatting.

## Requirements for Contributors

If you plan to contribute a patch, you need to build Google Test, Google Mock,
and their own tests from a git checkout, which has further requirements:

*   [Python](https://www.python.org/) v3.6 or newer (for running some of the
    tests and re-generating certain source files from templates)
*   [CMake](https://cmake.org/) v2.8.12 or newer

## Developing Google Test and Google Mock

This section discusses how to make your own changes to the Google Test project.

### Testing Google Test and Google Mock Themselves

To make sure your changes work as intended and don't break existing
functionality, you'll want to compile and run Google Test and GoogleMock's own
tests. For that you can use CMake:

```
mkdir mybuild
cd mybuild
cmake -Dgtest_build_tests=ON -Dgmock_build_tests=ON ${GTEST_REPO_DIR}
```

To choose between building only Google Test or Google Mock, you may modify your
cmake command to be one of each

```
cmake -Dgtest_build_tests=ON ${GTEST_DIR} # sets up Google Test tests
cmake -Dgmock_build_tests=ON ${GMOCK_DIR} # sets up Google Mock tests
```

Make sure you have Python installed, as some of Google Test's tests are written
in Python. If the cmake command complains about not being able to find Python
(`Could NOT find PythonInterp (missing: PYTHON_EXECUTABLE)`), try telling it
explicitly where your Python executable can be found:

```
cmake -DPYTHON_EXECUTABLE=path/to/python ...
```

Next, you can build Google Test and / or Google Mock and all desired tests. On
\*nix, this is usually done by

```
make
```

To run the tests, do

```
make test
```

All tests should pass.
gperftools-gperftools-2.18/vendor/googletest/CONTRIBUTORS000066400000000000000000000043651513545575200233670ustar00rootroot00000000000000# This file contains a list of people who've made non-trivial
# contribution to the Google C++ Testing Framework project.  People
# who commit code to the project are encouraged to add their names
# here.  Please keep the list sorted by first names.

Ajay Joshi 
Balázs Dán 
Benoit Sigoure 
Bharat Mediratta 
Bogdan Piloca 
Chandler Carruth 
Chris Prince 
Chris Taylor 
Dan Egnor 
Dave MacLachlan 
David Anderson 
Dean Sturtevant
Eric Roman 
Gene Volovich 
Hady Zalek 
Hal Burch 
Jeffrey Yasskin 
Jim Keller 
Joe Walnes 
Jon Wray 
Jói Sigurðsson 
Keir Mierle 
Keith Ray 
Kenton Varda 
Kostya Serebryany 
Krystian Kuzniarek 
Lev Makhlis
Manuel Klimek 
Mario Tanev 
Mark Paskin
Markus Heule 
Martijn Vels 
Matthew Simmons 
Mika Raento 
Mike Bland 
Miklós Fazekas 
Neal Norwitz 
Nermin Ozkiranartli 
Owen Carlsen 
Paneendra Ba 
Pasi Valminen 
Patrick Hanna 
Patrick Riley 
Paul Menage 
Peter Kaminski 
Piotr Kaminski 
Preston Jackson 
Rainer Klaffenboeck 
Russ Cox 
Russ Rufer 
Sean Mcafee 
Sigurður Ásgeirsson 
Soyeon Kim 
Sverre Sundsdal 
Szymon Sobik 
Takeshi Yoshino 
Tracy Bialik 
Vadim Berman 
Vlad Losev 
Wolfgang Klier 
Zhanyong Wan 
gperftools-gperftools-2.18/vendor/googletest/LICENSE000066400000000000000000000027031513545575200225060ustar00rootroot00000000000000Copyright 2008, Google Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
    * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
gperftools-gperftools-2.18/vendor/googletest/MODULE.bazel000066400000000000000000000051201513545575200235010ustar00rootroot00000000000000# Copyright 2024 Google Inc.
# All Rights Reserved.
#
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# https://bazel.build/external/overview#bzlmod

module(
    name = "googletest",
    version = "head",
    compatibility_level = 1,
)

# Only direct dependencies need to be listed below.
# Please keep the versions in sync with the versions in the WORKSPACE file.

bazel_dep(
    name = "abseil-cpp",
    version = "20250512.0",
)
bazel_dep(
    name = "platforms",
    version = "0.0.11",
)
bazel_dep(
    name = "re2",
    version = "2024-07-02.bcr.1",
)

bazel_dep(
    name = "rules_python",
    version = "1.3.0",
    dev_dependency = True,
)

# https://rules-python.readthedocs.io/en/stable/toolchains.html#library-modules-with-dev-only-python-usage
python = use_extension(
    "@rules_python//python/extensions:python.bzl",
    "python",
    dev_dependency = True,
)
python.toolchain(
    ignore_root_user_error = True,
    is_default = True,
    python_version = "3.12",
)

# See fake_fuchsia_sdk.bzl for instructions on how to override this with a real SDK, if needed.
fuchsia_sdk = use_extension("//:fake_fuchsia_sdk.bzl", "fuchsia_sdk")
fuchsia_sdk.create_fake()
use_repo(fuchsia_sdk, "fuchsia_sdk")
gperftools-gperftools-2.18/vendor/googletest/README.md000066400000000000000000000122151513545575200227570ustar00rootroot00000000000000# GoogleTest

### Announcements

#### Documentation Updates

Our documentation is now live on GitHub Pages at
https://google.github.io/googletest/. We recommend browsing the documentation on
GitHub Pages rather than directly in the repository.

#### Release 1.17.0

[Release 1.17.0](https://github.com/google/googletest/releases/tag/v1.17.0) is
now available.

The 1.17.x branch
[requires at least C++17](https://opensource.google/documentation/policies/cplusplus-support#c_language_standard).

#### Continuous Integration

We use Google's internal systems for continuous integration.

#### Coming Soon

*   We are planning to take a dependency on
    [Abseil](https://github.com/abseil/abseil-cpp).

## Welcome to **GoogleTest**, Google's C++ test framework!

This repository is a merger of the formerly separate GoogleTest and GoogleMock
projects. These were so closely related that it makes sense to maintain and
release them together.

### Getting Started

See the [GoogleTest User's Guide](https://google.github.io/googletest/) for
documentation. We recommend starting with the
[GoogleTest Primer](https://google.github.io/googletest/primer.html).

More information about building GoogleTest can be found at
[googletest/README.md](googletest/README.md).

## Features

*   xUnit test framework: \
    Googletest is based on the [xUnit](https://en.wikipedia.org/wiki/XUnit)
    testing framework, a popular architecture for unit testing
*   Test discovery: \
    Googletest automatically discovers and runs your tests, eliminating the need
    to manually register your tests
*   Rich set of assertions: \
    Googletest provides a variety of assertions, such as equality, inequality,
    exceptions, and more, making it easy to test your code
*   User-defined assertions: \
    You can define your own assertions with Googletest, making it simple to
    write tests that are specific to your code
*   Death tests: \
    Googletest supports death tests, which verify that your code exits in a
    certain way, making it useful for testing error-handling code
*   Fatal and non-fatal failures: \
    You can specify whether a test failure should be treated as fatal or
    non-fatal with Googletest, allowing tests to continue running even if a
    failure occurs
*   Value-parameterized tests: \
    Googletest supports value-parameterized tests, which run multiple times with
    different input values, making it useful for testing functions that take
    different inputs
*   Type-parameterized tests: \
    Googletest also supports type-parameterized tests, which run with different
    data types, making it useful for testing functions that work with different
    data types
*   Various options for running tests: \
    Googletest provides many options for running tests including running
    individual tests, running tests in a specific order and running tests in
    parallel

## Supported Platforms

GoogleTest follows Google's
[Foundational C++ Support Policy](https://opensource.google/documentation/policies/cplusplus-support).
See
[this table](https://github.com/google/oss-policies-info/blob/main/foundational-cxx-support-matrix.md)
for a list of currently supported versions of compilers, platforms, and build
tools.

## Who Is Using GoogleTest?

In addition to many internal projects at Google, GoogleTest is also used by the
following notable projects:

*   The [Chromium projects](https://www.chromium.org/) (behind the Chrome
    browser and Chrome OS).
*   The [LLVM](https://llvm.org/) compiler.
*   [Protocol Buffers](https://github.com/google/protobuf), Google's data
    interchange format.
*   The [OpenCV](https://opencv.org/) computer vision library.

## Related Open Source Projects

[GTest Runner](https://github.com/nholthaus/gtest-runner) is a Qt5 based
automated test-runner and Graphical User Interface with powerful features for
Windows and Linux platforms.

[GoogleTest UI](https://github.com/ospector/gtest-gbar) is a test runner that
runs your test binary, allows you to track its progress via a progress bar, and
displays a list of test failures. Clicking on one shows failure text. GoogleTest
UI is written in C#.

[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event
listener for GoogleTest that implements the
[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test
result output. If your test runner understands TAP, you may find it useful.

[gtest-parallel](https://github.com/google/gtest-parallel) is a test runner that
runs tests from your binary in parallel to provide significant speed-up.

[GoogleTest Adapter](https://marketplace.visualstudio.com/items?itemName=DavidSchuldenfrei.gtest-adapter)
is a VS Code extension allowing to view GoogleTest in a tree view and run/debug
your tests.

[C++ TestMate](https://github.com/matepek/vscode-catch2-test-adapter) is a VS
Code extension allowing to view GoogleTest in a tree view and run/debug your
tests.

[Cornichon](https://pypi.org/project/cornichon/) is a small Gherkin DSL parser
that generates stub code for GoogleTest.

## Contributing Changes

Please read
[`CONTRIBUTING.md`](https://github.com/google/googletest/blob/main/CONTRIBUTING.md)
for details on how to contribute to this project.

Happy testing!
gperftools-gperftools-2.18/vendor/googletest/WORKSPACE000066400000000000000000000052251513545575200227640ustar00rootroot00000000000000# Copyright 2024 Google Inc.
# All Rights Reserved.
#
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

workspace(name = "googletest")

load("//:googletest_deps.bzl", "googletest_deps")
googletest_deps()

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "rules_python",
    sha256 = "2cc26bbd53854ceb76dd42a834b1002cd4ba7f8df35440cf03482e045affc244",
    strip_prefix = "rules_python-1.3.0",
    url = "https://github.com/bazelbuild/rules_python/releases/download/1.3.0/rules_python-1.3.0.tar.gz",
)
# https://github.com/bazelbuild/rules_python/releases/tag/1.1.0
load("@rules_python//python:repositories.bzl", "py_repositories")
py_repositories()

http_archive(
  name = "bazel_skylib",
  sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94",
  urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz"],
)

http_archive(
    name = "platforms",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz",
        "https://github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz",
    ],
    sha256 = "29742e87275809b5e598dc2f04d86960cc7a55b3067d97221c9abbc9926bff0f",
)
gperftools-gperftools-2.18/vendor/googletest/WORKSPACE.bzlmod000066400000000000000000000034021513545575200242450ustar00rootroot00000000000000# Copyright 2024 Google Inc.
# All Rights Reserved.
#
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# https://bazel.build/external/migration#workspace.bzlmod
#
# This file is intentionally empty. When bzlmod is enabled and this
# file exists, the content of WORKSPACE is ignored. This prevents
# bzlmod builds from unintentionally depending on the WORKSPACE file.
gperftools-gperftools-2.18/vendor/googletest/ci/000077500000000000000000000000001513545575200220725ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/ci/linux-presubmit.sh000066400000000000000000000135251513545575200256030ustar00rootroot00000000000000#!/bin/bash
#
# Copyright 2020, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

set -euox pipefail

readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430"
readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250430"

if [[ -z ${GTEST_ROOT:-} ]]; then
  GTEST_ROOT="$(realpath $(dirname ${0})/..)"
fi

# Use Bazel Vendor mode to reduce reliance on external dependencies.
# See https://bazel.build/external/vendor and the Dockerfile for
# an explaination of how this works.
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" ]]; then
  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/googletest_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}"
  BAZEL_EXTRA_ARGS="--vendor_dir=/googletest_vendor ${BAZEL_EXTRA_ARGS:-}"
fi

if [[ -z ${STD:-} ]]; then
  STD="c++17 c++20 c++23"
fi

# Test CMake + GCC
for cmake_off_on in OFF ON; do
  time docker run \
    --volume="${GTEST_ROOT}:/src:ro" \
    --tmpfs="/build:exec" \
    --workdir="/build" \
    --rm \
    --env="CC=/usr/local/bin/gcc" \
    --env=CXXFLAGS="-Werror -Wdeprecated" \
    ${LINUX_LATEST_CONTAINER} \
    /bin/bash -c "
      cmake /src \
        -DCMAKE_CXX_STANDARD=17 \
        -Dgtest_build_samples=ON \
        -Dgtest_build_tests=ON \
        -Dgmock_build_tests=ON \
        -Dcxx_no_exception=${cmake_off_on} \
        -Dcxx_no_rtti=${cmake_off_on} && \
      make -j$(nproc) && \
      ctest -j$(nproc) --output-on-failure"
done

# Test CMake + Clang
for cmake_off_on in OFF ON; do
  time docker run \
    --volume="${GTEST_ROOT}:/src:ro" \
    --tmpfs="/build:exec" \
    --workdir="/build" \
    --rm \
    --env="CC=/opt/llvm/clang/bin/clang" \
    --env=CXXFLAGS="-Werror -Wdeprecated --gcc-toolchain=/usr/local" \
    ${LINUX_LATEST_CONTAINER} \
    /bin/bash -c "
      cmake /src \
        -DCMAKE_CXX_STANDARD=17 \
        -Dgtest_build_samples=ON \
        -Dgtest_build_tests=ON \
        -Dgmock_build_tests=ON \
        -Dcxx_no_exception=${cmake_off_on} \
        -Dcxx_no_rtti=${cmake_off_on} && \
      make -j$(nproc) && \
      ctest -j$(nproc) --output-on-failure"
done

# Do one test with an older version of GCC
time docker run \
  --volume="${GTEST_ROOT}:/src:ro" \
  --workdir="/src" \
  --rm \
  --env="CC=/usr/local/bin/gcc" \
  --env="BAZEL_CXXOPTS=-std=c++17" \
  ${DOCKER_EXTRA_ARGS:-} \
  ${LINUX_GCC_FLOOR_CONTAINER} \
  /bin/bash --login -c "
    /usr/local/bin/bazel test ... \
      --copt=\"-Wall\" \
      --copt=\"-Werror\" \
      --copt=\"-Wuninitialized\" \
      --copt=\"-Wundef\" \
      --copt=\"-Wno-error=pragmas\" \
      --enable_bzlmod=false \
      --features=external_include_paths \
      --keep_going \
      --show_timestamps \
      --test_output=errors \
      ${BAZEL_EXTRA_ARGS:-}"

# Test GCC
for std in ${STD}; do
  for absl in 0 1; do
    time docker run \
      --volume="${GTEST_ROOT}:/src:ro" \
      --workdir="/src" \
      --rm \
      --env="CC=/usr/local/bin/gcc" \
      --env="BAZEL_CXXOPTS=-std=${std}" \
      ${DOCKER_EXTRA_ARGS:-} \
      ${LINUX_LATEST_CONTAINER} \
      /bin/bash --login -c "
        /usr/local/bin/bazel test ... \
          --copt=\"-Wall\" \
          --copt=\"-Werror\" \
          --copt=\"-Wuninitialized\" \
          --copt=\"-Wundef\" \
          --define=\"absl=${absl}\" \
          --enable_bzlmod=true \
          --features=external_include_paths \
          --keep_going \
          --show_timestamps \
          --test_output=errors \
          ${BAZEL_EXTRA_ARGS:-}"
  done
done

# Test Clang
for std in ${STD}; do
  for absl in 0 1; do
    time docker run \
      --volume="${GTEST_ROOT}:/src:ro" \
      --workdir="/src" \
      --rm \
      --env="CC=/opt/llvm/clang/bin/clang" \
      --env="BAZEL_CXXOPTS=-std=${std}" \
      ${DOCKER_EXTRA_ARGS:-} \
      ${LINUX_LATEST_CONTAINER} \
      /bin/bash --login -c "
        /usr/local/bin/bazel test ... \
          --copt=\"--gcc-toolchain=/usr/local\" \
          --copt=\"-Wall\" \
          --copt=\"-Werror\" \
          --copt=\"-Wuninitialized\" \
          --copt=\"-Wundef\" \
          --define=\"absl=${absl}\" \
          --enable_bzlmod=true \
          --features=external_include_paths \
          --keep_going \
          --linkopt=\"--gcc-toolchain=/usr/local\" \
          --show_timestamps \
          --test_output=errors \
          ${BAZEL_EXTRA_ARGS:-}"
  done
done
gperftools-gperftools-2.18/vendor/googletest/ci/macos-presubmit.sh000066400000000000000000000061701513545575200255440ustar00rootroot00000000000000#!/bin/bash
#
# Copyright 2020, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

set -euox pipefail

# Use Xcode 16.0
sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer

if [[ -z ${GTEST_ROOT:-} ]]; then
  GTEST_ROOT="$(realpath $(dirname ${0})/..)"
fi

# Test the CMake build
for cmake_off_on in OFF ON; do
  BUILD_DIR=$(mktemp -d build_dir.XXXXXXXX)
  cd ${BUILD_DIR}
  time cmake ${GTEST_ROOT} \
    -DCMAKE_CXX_STANDARD=17 \
    -Dgtest_build_samples=ON \
    -Dgtest_build_tests=ON \
    -Dgmock_build_tests=ON \
    -Dcxx_no_exception=${cmake_off_on} \
    -Dcxx_no_rtti=${cmake_off_on}
  time make -j$(nproc)
  time ctest -j$(nproc) --output-on-failure
done

# Test the Bazel build

# If we are running on Kokoro, check for a versioned Bazel binary.
KOKORO_GFILE_BAZEL_BIN="bazel-8.2.1-darwin-x86_64"
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then
  BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}"
  chmod +x ${BAZEL_BIN}
else
  BAZEL_BIN="bazel"
fi

# Use Bazel Vendor mode to reduce reliance on external dependencies.
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" ]]; then
  tar -xf "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" -C "${TMP}/"
  BAZEL_EXTRA_ARGS="--vendor_dir=\"${TMP}/googletest_vendor\" ${BAZEL_EXTRA_ARGS:-}"
fi

cd ${GTEST_ROOT}
for absl in 0 1; do
  ${BAZEL_BIN} test ... \
    --copt="-Wall" \
    --copt="-Werror" \
    --copt="-Wundef" \
    --cxxopt="-std=c++17" \
    --define="absl=${absl}" \
    --enable_bzlmod=true \
    --features=external_include_paths \
    --keep_going \
    --show_timestamps \
    --test_output=errors \
    ${BAZEL_EXTRA_ARGS:-}
done
gperftools-gperftools-2.18/vendor/googletest/ci/windows-presubmit.bat000066400000000000000000000045431513545575200262720ustar00rootroot00000000000000SETLOCAL ENABLEDELAYEDEXPANSION

SET BAZEL_EXE=%KOKORO_GFILE_DIR%\bazel-8.2.1-windows-x86_64.exe

SET PATH=C:\Python34;%PATH%
SET BAZEL_PYTHON=C:\python34\python.exe
SET BAZEL_SH=C:\tools\msys64\usr\bin\bash.exe
SET CMAKE_BIN="cmake.exe"
SET CTEST_BIN="ctest.exe"
SET CTEST_OUTPUT_ON_FAILURE=1
SET CMAKE_BUILD_PARALLEL_LEVEL=16
SET CTEST_PARALLEL_LEVEL=16

SET GTEST_ROOT=%~dp0\..
IF %errorlevel% neq 0 EXIT /B 1

:: ----------------------------------------------------------------------------
:: CMake
SET CMAKE_BUILD_PATH=cmake_msvc2022
MKDIR %CMAKE_BUILD_PATH%
CD %CMAKE_BUILD_PATH%

%CMAKE_BIN% %GTEST_ROOT% ^
  -G "Visual Studio 17 2022" ^
  -DCMAKE_CXX_STANDARD=17 ^
  -DPYTHON_EXECUTABLE:FILEPATH=c:\python37\python.exe ^
  -DPYTHON_INCLUDE_DIR:PATH=c:\python37\include ^
  -DPYTHON_LIBRARY:FILEPATH=c:\python37\lib\site-packages\pip ^
  -Dgtest_build_samples=ON ^
  -Dgtest_build_tests=ON ^
  -Dgmock_build_tests=ON
IF %errorlevel% neq 0 EXIT /B 1

%CMAKE_BIN% --build . --target ALL_BUILD --config Debug -- -maxcpucount
IF %errorlevel% neq 0 EXIT /B 1

%CTEST_BIN% -C Debug --timeout 600
IF %errorlevel% neq 0 EXIT /B 1

CD %GTEST_ROOT%
RMDIR /S /Q %CMAKE_BUILD_PATH%

:: ----------------------------------------------------------------------------
:: Bazel

:: The default home directory on Kokoro is a long path which causes errors
:: because of Windows limitations on path length.
:: --output_user_root=C:\tmp causes Bazel to use a shorter path.
SET BAZEL_VS=C:\Program Files\Microsoft Visual Studio\2022\Community

:: Use Bazel Vendor mode to reduce reliance on external dependencies.
IF EXIST "%KOKORO_GFILE_DIR%\distdir\googletest_vendor.tar.gz" (
  tar --force-local -xf "%KOKORO_GFILE_DIR%\distdir\googletest_vendor.tar.gz" -C c:
  SET VENDOR_FLAG=--vendor_dir=c:\googletest_vendor
) ELSE (
  SET VENDOR_FLAG=
)

:: C++17
%BAZEL_EXE% ^
  --output_user_root=C:\tmp ^
  test ... ^
  --compilation_mode=dbg ^
  --copt=/std:c++17 ^
  --copt=/WX ^
  --enable_bzlmod=true ^
  --keep_going ^
  --test_output=errors ^
  --test_tag_filters=-no_test_msvc2017 ^
  %VENDOR_FLAG%
IF %errorlevel% neq 0 EXIT /B 1

:: C++20
%BAZEL_EXE% ^
  --output_user_root=C:\tmp ^
  test ... ^
  --compilation_mode=dbg ^
  --copt=/std:c++20 ^
  --copt=/WX ^
  --enable_bzlmod=true ^
  --keep_going ^
  --test_output=errors ^
  --test_tag_filters=-no_test_msvc2017 ^
  %VENDOR_FLAG%
IF %errorlevel% neq 0 EXIT /B 1
gperftools-gperftools-2.18/vendor/googletest/docs/000077500000000000000000000000001513545575200224275ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/docs/_config.yml000066400000000000000000000000221513545575200245500ustar00rootroot00000000000000title: GoogleTest
gperftools-gperftools-2.18/vendor/googletest/docs/_data/000077500000000000000000000000001513545575200234775ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/docs/_data/navigation.yml000066400000000000000000000022601513545575200263610ustar00rootroot00000000000000nav:
- section: "Get Started"
  items:
  - title: "Supported Platforms"
    url: "/platforms.html"
  - title: "Quickstart: Bazel"
    url: "/quickstart-bazel.html"
  - title: "Quickstart: CMake"
    url: "/quickstart-cmake.html"
- section: "Guides"
  items:
  - title: "GoogleTest Primer"
    url: "/primer.html"
  - title: "Advanced Topics"
    url: "/advanced.html"
  - title: "Mocking for Dummies"
    url: "/gmock_for_dummies.html"
  - title: "Mocking Cookbook"
    url: "/gmock_cook_book.html"
  - title: "Mocking Cheat Sheet"
    url: "/gmock_cheat_sheet.html"
- section: "References"
  items:
  - title: "Testing Reference"
    url: "/reference/testing.html"
  - title: "Mocking Reference"
    url: "/reference/mocking.html"
  - title: "Assertions"
    url: "/reference/assertions.html"
  - title: "Matchers"
    url: "/reference/matchers.html"
  - title: "Actions"
    url: "/reference/actions.html"
  - title: "Testing FAQ"
    url: "/faq.html"
  - title: "Mocking FAQ"
    url: "/gmock_faq.html"
  - title: "Code Samples"
    url: "/samples.html"
  - title: "Using pkg-config"
    url: "/pkgconfig.html"
  - title: "Community Documentation"
    url: "/community_created_documentation.html"
gperftools-gperftools-2.18/vendor/googletest/docs/_layouts/000077500000000000000000000000001513545575200242665ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/docs/_layouts/default.html000066400000000000000000000042131513545575200266000ustar00rootroot00000000000000

  
    
    
    

{% seo %}
    
    
    
    
  
  
    
    
{{ content }}
gperftools-gperftools-2.18/vendor/googletest/docs/_sass/000077500000000000000000000000001513545575200235375ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/docs/_sass/main.scss000066400000000000000000000055431513545575200253670ustar00rootroot00000000000000// Styles for GoogleTest docs website on GitHub Pages. // Color variables are defined in // https://github.com/pages-themes/primer/tree/master/_sass/primer-support/lib/variables $sidebar-width: 260px; body { display: flex; margin: 0; } .sidebar { background: $black; color: $text-white; flex-shrink: 0; height: 100vh; overflow: auto; position: sticky; top: 0; width: $sidebar-width; } .sidebar h1 { font-size: 1.5em; } .sidebar h2 { color: $gray-light; font-size: 0.8em; font-weight: normal; margin-bottom: 0.8em; padding-left: 2.5em; text-transform: uppercase; } .sidebar .header { background: $black; padding: 2em; position: sticky; top: 0; width: 100%; } .sidebar .header a { color: $text-white; text-decoration: none; } .sidebar .nav-toggle { display: none; } .sidebar .expander { cursor: pointer; display: none; height: 3em; position: absolute; right: 1em; top: 1.5em; width: 3em; } .sidebar .expander .arrow { border: solid $white; border-width: 0 3px 3px 0; display: block; height: 0.7em; margin: 1em auto; transform: rotate(45deg); transition: transform 0.5s; width: 0.7em; } .sidebar nav { width: 100%; } .sidebar nav ul { list-style-type: none; margin-bottom: 1em; padding: 0; &:last-child { margin-bottom: 2em; } a { text-decoration: none; } li { color: $text-white; padding-left: 2em; text-decoration: none; } li.active { background: $border-gray-darker; font-weight: bold; } li:hover { background: $border-gray-darker; } } .main { background-color: $bg-gray; width: calc(100% - #{$sidebar-width}); } .main .main-inner { background-color: $white; padding: 2em; } .main .footer { margin: 0; padding: 2em; } .main table th { text-align: left; } .main .callout { border-left: 0.25em solid $white; padding: 1em; a { text-decoration: underline; } &.important { background-color: $bg-yellow-light; border-color: $bg-yellow; color: $black; } &.note { background-color: $bg-blue-light; border-color: $text-blue; color: $text-blue; } &.tip { background-color: $green-000; border-color: $green-700; color: $green-700; } &.warning { background-color: $red-000; border-color: $text-red; color: $text-red; } } .main .good pre { background-color: $bg-green-light; } .main .bad pre { background-color: $red-000; } @media all and (max-width: 768px) { body { flex-direction: column; } .sidebar { height: auto; position: relative; width: 100%; } .sidebar .expander { display: block; } .sidebar nav { height: 0; overflow: hidden; } .sidebar .nav-toggle:checked { & ~ nav { height: auto; } & + .expander .arrow { transform: rotate(-135deg); } } .main { width: 100%; } } gperftools-gperftools-2.18/vendor/googletest/docs/advanced.md000066400000000000000000002613761513545575200245350ustar00rootroot00000000000000# Advanced GoogleTest Topics ## Introduction Now that you have read the [GoogleTest Primer](primer.md) and learned how to write tests using GoogleTest, it's time to learn some new tricks. This document will show you more assertions as well as how to construct complex failure messages, propagate fatal failures, reuse and speed up your test fixtures, and use various flags with your tests. ## More Assertions This section covers some less frequently used, but still significant, assertions. ### Explicit Success and Failure See [Explicit Success and Failure](reference/assertions.md#success-failure) in the Assertions Reference. ### Exception Assertions See [Exception Assertions](reference/assertions.md#exceptions) in the Assertions Reference. ### Predicate Assertions for Better Error Messages Even though GoogleTest has a rich set of assertions, they can never be complete, as it's impossible (nor a good idea) to anticipate all scenarios a user might run into. Therefore, sometimes a user has to use `EXPECT_TRUE()` to check a complex expression, for lack of a better macro. This has the problem of not showing you the values of the parts of the expression, making it hard to understand what went wrong. As a workaround, some users choose to construct the failure message by themselves, streaming it into `EXPECT_TRUE()`. However, this is awkward especially when the expression has side-effects or is expensive to evaluate. GoogleTest gives you three different options to solve this problem: #### Using an Existing Boolean Function If you already have a function or functor that returns `bool` (or a type that can be implicitly converted to `bool`), you can use it in a *predicate assertion* to get the function arguments printed for free. See [`EXPECT_PRED*`](reference/assertions.md#EXPECT_PRED) in the Assertions Reference for details. #### Using a Function That Returns an AssertionResult While `EXPECT_PRED*()` and friends are handy for a quick job, the syntax is not satisfactory: you have to use different macros for different arities, and it feels more like Lisp than C++. The `::testing::AssertionResult` class solves this problem. An `AssertionResult` object represents the result of an assertion (whether it's a success or a failure, and an associated message). You can create an `AssertionResult` using one of these factory functions: ```c++ namespace testing { // Returns an AssertionResult object to indicate that an assertion has // succeeded. AssertionResult AssertionSuccess(); // Returns an AssertionResult object to indicate that an assertion has // failed. AssertionResult AssertionFailure(); } ``` You can then use the `<<` operator to stream messages to the `AssertionResult` object. To provide more readable messages in Boolean assertions (e.g. `EXPECT_TRUE()`), write a predicate function that returns `AssertionResult` instead of `bool`. For example, if you define `IsEven()` as: ```c++ testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return testing::AssertionSuccess(); else return testing::AssertionFailure() << n << " is odd"; } ``` instead of: ```c++ bool IsEven(int n) { return (n % 2) == 0; } ``` the failed assertion `EXPECT_TRUE(IsEven(Fib(4)))` will print: ```none Value of: IsEven(Fib(4)) Actual: false (3 is odd) Expected: true ``` instead of a more opaque ```none Value of: IsEven(Fib(4)) Actual: false Expected: true ``` If you want informative messages in `EXPECT_FALSE` and `ASSERT_FALSE` as well (one third of Boolean assertions in the Google code base are negative ones), and are fine with making the predicate slower in the success case, you can supply a success message: ```c++ testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return testing::AssertionSuccess() << n << " is even"; else return testing::AssertionFailure() << n << " is odd"; } ``` Then the statement `EXPECT_FALSE(IsEven(Fib(6)))` will print ```none Value of: IsEven(Fib(6)) Actual: true (8 is even) Expected: false ``` #### Using a Predicate-Formatter If you find the default message generated by [`EXPECT_PRED*`](reference/assertions.md#EXPECT_PRED) and [`EXPECT_TRUE`](reference/assertions.md#EXPECT_TRUE) unsatisfactory, or some arguments to your predicate do not support streaming to `ostream`, you can instead use *predicate-formatter assertions* to *fully* customize how the message is formatted. See [`EXPECT_PRED_FORMAT*`](reference/assertions.md#EXPECT_PRED_FORMAT) in the Assertions Reference for details. ### Floating-Point Comparison See [Floating-Point Comparison](reference/assertions.md#floating-point) in the Assertions Reference. #### Floating-Point Predicate-Format Functions Some floating-point operations are useful, but not that often used. In order to avoid an explosion of new macros, we provide them as predicate-format functions that can be used in the predicate assertion macro [`EXPECT_PRED_FORMAT2`](reference/assertions.md#EXPECT_PRED_FORMAT), for example: ```c++ using ::testing::FloatLE; using ::testing::DoubleLE; ... EXPECT_PRED_FORMAT2(FloatLE, val1, val2); EXPECT_PRED_FORMAT2(DoubleLE, val1, val2); ``` The above code verifies that `val1` is less than, or approximately equal to, `val2`. ### Asserting Using gMock Matchers See [`EXPECT_THAT`](reference/assertions.md#EXPECT_THAT) in the Assertions Reference. ### More String Assertions (Please read the [previous](#asserting-using-gmock-matchers) section first if you haven't.) You can use the gMock [string matchers](reference/matchers.md#string-matchers) with [`EXPECT_THAT`](reference/assertions.md#EXPECT_THAT) to do more string comparison tricks (sub-string, prefix, suffix, regular expression, and etc). For example, ```c++ using ::testing::HasSubstr; using ::testing::MatchesRegex; ... ASSERT_THAT(foo_string, HasSubstr("needle")); EXPECT_THAT(bar_string, MatchesRegex("\\w*\\d+")); ``` ### Windows HRESULT assertions See [Windows HRESULT Assertions](reference/assertions.md#HRESULT) in the Assertions Reference. ### Type Assertions You can call the function ```c++ ::testing::StaticAssertTypeEq(); ``` to assert that types `T1` and `T2` are the same. The function does nothing if the assertion is satisfied. If the types are different, the function call will fail to compile, the compiler error message will say that `T1 and T2 are not the same type` and most likely (depending on the compiler) show you the actual values of `T1` and `T2`. This is mainly useful inside template code. **Caveat**: When used inside a member function of a class template or a function template, `StaticAssertTypeEq()` is effective only if the function is instantiated. For example, given: ```c++ template class Foo { public: void Bar() { testing::StaticAssertTypeEq(); } }; ``` the code: ```c++ void Test1() { Foo foo; } ``` will not generate a compiler error, as `Foo::Bar()` is never actually instantiated. Instead, you need: ```c++ void Test2() { Foo foo; foo.Bar(); } ``` to cause a compiler error. ### Assertion Placement You can use assertions in any C++ function. In particular, it doesn't have to be a method of the test fixture class. The one constraint is that assertions that generate a fatal failure (`FAIL*` and `ASSERT_*`) can only be used in void-returning functions. This is a consequence of Google's not using exceptions. By placing it in a non-void function you'll get a confusing compile error like `"error: void value not ignored as it ought to be"` or `"cannot initialize return object of type 'bool' with an rvalue of type 'void'"` or `"error: no viable conversion from 'void' to 'string'"`. If you need to use fatal assertions in a function that returns non-void, one option is to make the function return the value in an out parameter instead. For example, you can rewrite `T2 Foo(T1 x)` to `void Foo(T1 x, T2* result)`. You need to make sure that `*result` contains some sensible value even when the function returns prematurely. As the function now returns `void`, you can use any assertion inside of it. If changing the function's type is not an option, you should just use assertions that generate non-fatal failures, such as `ADD_FAILURE*` and `EXPECT_*`. {: .callout .note} NOTE: Constructors and destructors are not considered void-returning functions, according to the C++ language specification, and so you may not use fatal assertions in them; you'll get a compilation error if you try. Instead, either call `abort` and crash the entire test executable, or put the fatal assertion in a `SetUp`/`TearDown` function; see [constructor/destructor vs. `SetUp`/`TearDown`](faq.md#CtorVsSetUp) {: .callout .warning} WARNING: A fatal assertion in a helper function (private void-returning method) called from a constructor or destructor does not terminate the current test, as your intuition might suggest: it merely returns from the constructor or destructor early, possibly leaving your object in a partially-constructed or partially-destructed state! You almost certainly want to `abort` or use `SetUp`/`TearDown` instead. ## Skipping test execution Related to the assertions `SUCCEED()` and `FAIL()`, you can prevent further test execution at runtime with the `GTEST_SKIP()` macro. This is useful when you need to check for preconditions of the system under test during runtime and skip tests in a meaningful way. `GTEST_SKIP()` can be used in individual test cases or in the `SetUp()` methods of classes derived from either `::testing::Environment` or `::testing::Test`. For example: ```c++ TEST(SkipTest, DoesSkip) { GTEST_SKIP() << "Skipping single test"; FAIL(); // Won't fail; it won't be executed } class SkipFixture : public ::testing::Test { protected: void SetUp() override { GTEST_SKIP() << "Skipping all tests for this fixture"; } }; // Tests for SkipFixture won't be executed. TEST_F(SkipFixture, SkipsOneTest) { FAIL(); // Won't fail; it won't be executed } ``` As with assertion macros, you can stream a custom message into `GTEST_SKIP()`. ## Teaching GoogleTest How to Print Your Values When a test assertion such as `EXPECT_EQ` fails, GoogleTest prints the argument values to help you debug. It does this using a user-extensible value printer. This printer knows how to print built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hopes that you the user can figure it out. As mentioned earlier, the printer is *extensible*. That means you can teach it to do a better job at printing your particular type than to dump the bytes. To do that, define an `AbslStringify()` overload as a `friend` function template for your type: ```cpp namespace foo { class Point { // We want GoogleTest to be able to print instances of this. ... // Provide a friend overload. template friend void AbslStringify(Sink& sink, const Point& point) { absl::Format(&sink, "(%d, %d)", point.x, point.y); } int x; int y; }; // If you can't declare the function in the class it's important that the // AbslStringify overload is defined in the SAME namespace that defines Point. // C++'s look-up rules rely on that. enum class EnumWithStringify { kMany = 0, kChoices = 1 }; template void AbslStringify(Sink& sink, EnumWithStringify e) { absl::Format(&sink, "%s", e == EnumWithStringify::kMany ? "Many" : "Choices"); } } // namespace foo ``` {: .callout .note} Note: `AbslStringify()` utilizes a generic "sink" buffer to construct its string. For more information about supported operations on `AbslStringify()`'s sink, see [the `AbslStringify()` documentation](https://abseil.io/docs/cpp/guides/abslstringify). `AbslStringify()` can also use `absl::StrFormat`'s catch-all `%v` type specifier within its own format strings to perform type deduction. `Point` above could be formatted as `"(%v, %v)"` for example, and deduce the `int` values as `%d`. Sometimes, `AbslStringify()` might not be an option: your team may wish to print types with extra debugging information for testing purposes only. If so, you can instead define a `PrintTo()` function like this: ```c++ #include namespace foo { class Point { ... friend void PrintTo(const Point& point, std::ostream* os) { *os << "(" << point.x << "," << point.y << ")"; } int x; int y; }; // If you can't declare the function in the class it's important that PrintTo() // is defined in the SAME namespace that defines Point. C++'s look-up rules // rely on that. void PrintTo(const Point& point, std::ostream* os) { *os << "(" << point.x << "," << point.y << ")"; } } // namespace foo ``` If you have defined both `AbslStringify()` and `PrintTo()`, the latter will be used by GoogleTest. This allows you to customize how the value appears in GoogleTest's output without affecting code that relies on the behavior of `AbslStringify()`. If you have an existing `<<` operator and would like to define an `AbslStringify()`, the latter will be used for GoogleTest printing. If you want to print a value `x` using GoogleTest's value printer yourself, just call `::testing::PrintToString(x)`, which returns an `std::string`: ```c++ vector > point_ints = GetPointIntVector(); EXPECT_TRUE(IsCorrectPointIntVector(point_ints)) << "point_ints = " << testing::PrintToString(point_ints); ``` For more details regarding `AbslStringify()` and its integration with other libraries, see [the documentation](https://abseil.io/docs/cpp/guides/abslstringify). ## Regular Expression Syntax When built with Bazel and using Abseil, GoogleTest uses the [RE2](https://github.com/google/re2/wiki/Syntax) syntax. Otherwise, for POSIX systems (Linux, Cygwin, Mac), GoogleTest uses the [POSIX extended regular expression](https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) syntax. To learn about POSIX syntax, you may want to read this [Wikipedia entry](https://en.wikipedia.org/wiki/Regular_expression#POSIX_extended). On Windows, GoogleTest uses its own simple regular expression implementation. It lacks many features. For example, we don't support union (`"x|y"`), grouping (`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among others. Below is what we do support (`A` denotes a literal character, period (`.`), or a single `\\ ` escape sequence; `x` and `y` denote regular expressions.): Expression | Meaning ---------- | -------------------------------------------------------------- `c` | matches any literal character `c` `\\d` | matches any decimal digit `\\D` | matches any character that's not a decimal digit `\\f` | matches `\f` `\\n` | matches `\n` `\\r` | matches `\r` `\\s` | matches any ASCII whitespace, including `\n` `\\S` | matches any character that's not a whitespace `\\t` | matches `\t` `\\v` | matches `\v` `\\w` | matches any letter, `_`, or decimal digit `\\W` | matches any character that `\\w` doesn't match `\\c` | matches any literal character `c`, which must be a punctuation `.` | matches any single character except `\n` `A?` | matches 0 or 1 occurrences of `A` `A*` | matches 0 or many occurrences of `A` `A+` | matches 1 or many occurrences of `A` `^` | matches the beginning of a string (not that of each line) `$` | matches the end of a string (not that of each line) `xy` | matches `x` followed by `y` To help you determine which capability is available on your system, GoogleTest defines macros to govern which regular expression it is using. The macros are: `GTEST_USES_SIMPLE_RE=1` or `GTEST_USES_POSIX_RE=1`. If you want your death tests to work in all cases, you can either `#if` on these macros or use the more limited syntax only. ## Death Tests In many applications, there are assertions that can cause application failure if a condition is not met. These consistency checks, which ensure that the program is in a known good state, are there to fail at the earliest possible time after some program state is corrupted. If the assertion checks the wrong condition, then the program may proceed in an erroneous state, which could lead to memory corruption, security holes, or worse. Hence it is vitally important to test that such assertion statements work as expected. Since these precondition checks cause the processes to die, we call such tests *death tests*. More generally, any test that checks that a program terminates (except by throwing an exception) in an expected fashion is also a death test. Note that if a piece of code throws an exception, we don't consider it "death" for the purpose of death tests, as the caller of the code could catch the exception and avoid the crash. If you want to verify exceptions thrown by your code, see [Exception Assertions](#ExceptionAssertions). If you want to test `EXPECT_*()/ASSERT_*()` failures in your test code, see ["Catching" Failures](#catching-failures). ### How to Write a Death Test GoogleTest provides assertion macros to support death tests. See [Death Assertions](reference/assertions.md#death) in the Assertions Reference for details. To write a death test, simply use one of the macros inside your test function. For example, ```c++ TEST(MyDeathTest, Foo) { // This death test uses a compound statement. ASSERT_DEATH({ int n = 5; Foo(&n); }, "Error on line .* of Foo()"); } TEST(MyDeathTest, NormalExit) { EXPECT_EXIT(NormalExit(), testing::ExitedWithCode(0), "Success"); } TEST(MyDeathTest, KillProcess) { EXPECT_EXIT(KillProcess(), testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal"); } ``` verifies that: * calling `Foo(5)` causes the process to die with the given error message, * calling `NormalExit()` causes the process to print `"Success"` to stderr and exit with exit code 0, and * calling `KillProcess()` kills the process with signal `SIGKILL`. {: .callout .warning} Warning: If your death test contains mocks and is expecting a specific exit code, then you must allow the mock objects to be leaked via `Mock::AllowLeak`. This is because the mock leak detector will exit with its own error code if it detects a leak. The test function body may contain other assertions and statements as well, if necessary. Note that a death test only cares about three things: 1. does `statement` abort or exit the process? 2. (in the case of `ASSERT_EXIT` and `EXPECT_EXIT`) does the exit status satisfy `predicate`? Or (in the case of `ASSERT_DEATH` and `EXPECT_DEATH`) is the exit status non-zero? And 3. does the stderr output match `matcher`? In particular, if `statement` generates an `ASSERT_*` or `EXPECT_*` failure, it will **not** cause the death test to fail, as GoogleTest assertions don't abort the process. ### Death Test Naming {: .callout .important} IMPORTANT: We strongly recommend you to follow the convention of naming your **test suite** (not test) `*DeathTest` when it contains a death test, as demonstrated in the above example. The [Death Tests And Threads](#death-tests-and-threads) section below explains why. If a test fixture class is shared by normal tests and death tests, you can use `using` or `typedef` to introduce an alias for the fixture class and avoid duplicating its code: ```c++ class FooTest : public testing::Test { ... }; using FooDeathTest = FooTest; TEST_F(FooTest, DoesThis) { // normal test } TEST_F(FooDeathTest, DoesThat) { // death test } ``` ### How It Works See [Death Assertions](reference/assertions.md#death) in the Assertions Reference. ### Death Tests And Threads The reason for the two death test styles has to do with thread safety. Due to well-known problems with forking in the presence of threads, death tests should be run in a single-threaded context. Sometimes, however, it isn't feasible to arrange that kind of environment. For example, statically-initialized modules may start threads before main is ever reached. Once threads have been created, it may be difficult or impossible to clean them up. GoogleTest has three features intended to raise awareness of threading issues. 1. A warning is emitted if multiple threads are running when a death test is encountered. 2. Test suites with a name ending in "DeathTest" are run before all other tests. 3. It uses `clone()` instead of `fork()` to spawn the child process on Linux (`clone()` is not available on Cygwin and Mac), as `fork()` is more likely to cause the child to hang when the parent process has multiple threads. It's perfectly fine to create threads inside a death test statement; they are executed in a separate process and cannot affect the parent. ### Death Test Styles The "threadsafe" death test style was introduced in order to help mitigate the risks of testing in a possibly multithreaded environment. It trades increased test execution time (potentially dramatically so) for improved thread safety. The automated testing framework does not set the style flag. You can choose a particular style of death tests by setting the flag programmatically: ```c++ GTEST_FLAG_SET(death_test_style, "threadsafe"); ``` You can do this in `main()` to set the style for all death tests in the binary, or in individual tests. Recall that flags are saved before running each test and restored afterwards, so you need not do that yourself. For example: ```c++ int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); GTEST_FLAG_SET(death_test_style, "fast"); return RUN_ALL_TESTS(); } TEST(MyDeathTest, TestOne) { GTEST_FLAG_SET(death_test_style, "threadsafe"); // This test is run in the "threadsafe" style: ASSERT_DEATH(ThisShouldDie(), ""); } TEST(MyDeathTest, TestTwo) { // This test is run in the "fast" style: ASSERT_DEATH(ThisShouldDie(), ""); } ``` ### Caveats The `statement` argument of `ASSERT_EXIT()` can be any valid C++ statement. If it leaves the current function via a `return` statement or by throwing an exception, the death test is considered to have failed. Some GoogleTest macros may return from the current function (e.g. `ASSERT_TRUE()`), so be sure to avoid them in `statement`. Since `statement` runs in the child process, any in-memory side effect (e.g. modifying a variable, releasing memory, etc) it causes will *not* be observable in the parent process. In particular, if you release memory in a death test, your program will fail the heap check as the parent process will never see the memory reclaimed. To solve this problem, you can 1. try not to free memory in a death test; 2. free the memory again in the parent process; or 3. do not use the heap checker in your program. Due to an implementation detail, you cannot place multiple death test assertions on the same line; otherwise, compilation will fail with an unobvious error message. Despite the improved thread safety afforded by the "threadsafe" style of death test, thread problems such as deadlock are still possible in the presence of handlers registered with `pthread_atfork(3)`. ## Using Assertions in Sub-routines {: .callout .note} Note: If you want to put a series of test assertions in a subroutine to check for a complex condition, consider using [a custom GMock matcher](gmock_cook_book.md#NewMatchers) instead. This lets you provide a more readable error message in case of failure and avoid all of the issues described below. ### Adding Traces to Assertions If a test sub-routine is called from several places, when an assertion inside it fails, it can be hard to tell which invocation of the sub-routine the failure is from. You can alleviate this problem using extra logging or custom failure messages, but that usually clutters up your tests. A better solution is to use the `SCOPED_TRACE` macro or the `ScopedTrace` utility: ```c++ SCOPED_TRACE(message); ``` ```c++ ScopedTrace trace("file_path", line_number, message); ``` where `message` can be anything streamable to `std::ostream`. `SCOPED_TRACE` macro will cause the current file name, line number, and the given message to be added in every failure message. `ScopedTrace` accepts explicit file name and line number in arguments, which is useful for writing test helpers. The effect will be undone when the control leaves the current lexical scope. For example, ```c++ 10: void Sub1(int n) { 11: EXPECT_EQ(Bar(n), 1); 12: EXPECT_EQ(Bar(n + 1), 2); 13: } 14: 15: TEST(FooTest, Bar) { 16: { 17: SCOPED_TRACE("A"); // This trace point will be included in 18: // every failure in this scope. 19: Sub1(1); 20: } 21: // Now it won't. 22: Sub1(9); 23: } ``` could result in messages like these: ```none path/to/foo_test.cc:11: Failure Value of: Bar(n) Expected: 1 Actual: 2 Google Test trace: path/to/foo_test.cc:17: A path/to/foo_test.cc:12: Failure Value of: Bar(n + 1) Expected: 2 Actual: 3 ``` Without the trace, it would've been difficult to know which invocation of `Sub1()` the two failures come from respectively. (You could add an extra message to each assertion in `Sub1()` to indicate the value of `n`, but that's tedious.) Some tips on using `SCOPED_TRACE`: 1. With a suitable message, it's often enough to use `SCOPED_TRACE` at the beginning of a sub-routine, instead of at each call site. 2. When calling sub-routines inside a loop, make the loop iterator part of the message in `SCOPED_TRACE` such that you can know which iteration the failure is from. 3. Sometimes the line number of the trace point is enough for identifying the particular invocation of a sub-routine. In this case, you don't have to choose a unique message for `SCOPED_TRACE`. You can simply use `""`. 4. You can use `SCOPED_TRACE` in an inner scope when there is one in the outer scope. In this case, all active trace points will be included in the failure messages, in reverse order they are encountered. 5. The trace dump is clickable in Emacs - hit `return` on a line number and you'll be taken to that line in the source file! ### Propagating Fatal Failures A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that when they fail they only abort the *current function*, not the entire test. For example, the following test will segfault: ```c++ void Subroutine() { // Generates a fatal failure and aborts the current function. ASSERT_EQ(1, 2); // The following won't be executed. ... } TEST(FooTest, Bar) { Subroutine(); // The intended behavior is for the fatal failure // in Subroutine() to abort the entire test. // The actual behavior: the function goes on after Subroutine() returns. int* p = nullptr; *p = 3; // Segfault! } ``` To alleviate this, GoogleTest provides three different solutions. You could use either exceptions, the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the `HasFatalFailure()` function. They are described in the following two subsections. #### Asserting on Subroutines with an exception The following code can turn ASSERT-failure into an exception: ```c++ class ThrowListener : public testing::EmptyTestEventListener { void OnTestPartResult(const testing::TestPartResult& result) override { if (result.type() == testing::TestPartResult::kFatalFailure) { throw testing::AssertionException(result); } } }; int main(int argc, char** argv) { ... testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener); return RUN_ALL_TESTS(); } ``` This listener should be added after other listeners if you have any, otherwise they won't see failed `OnTestPartResult`. #### Asserting on Subroutines As shown above, if your test calls a subroutine that has an `ASSERT_*` failure in it, the test will continue after the subroutine returns. This may not be what you want. Often people want fatal failures to propagate like exceptions. For that GoogleTest offers the following macros: Fatal assertion | Nonfatal assertion | Verifies ------------------------------------- | ------------------------------------- | -------- `ASSERT_NO_FATAL_FAILURE(statement);` | `EXPECT_NO_FATAL_FAILURE(statement);` | `statement` doesn't generate any new fatal failures in the current thread. Only failures in the thread that executes the assertion are checked to determine the result of this type of assertions. If `statement` creates new threads, failures in these threads are ignored. Examples: ```c++ ASSERT_NO_FATAL_FAILURE(Foo()); int i; EXPECT_NO_FATAL_FAILURE({ i = Bar(); }); ``` Assertions from multiple threads are currently not supported on Windows. #### Checking for Failures in the Current Test `HasFatalFailure()` in the `::testing::Test` class returns `true` if an assertion in the current test has suffered a fatal failure. This allows functions to catch fatal failures in a sub-routine and return early. ```c++ class Test { public: ... static bool HasFatalFailure(); }; ``` The typical usage, which basically simulates the behavior of a thrown exception, is: ```c++ TEST(FooTest, Bar) { Subroutine(); // Aborts if Subroutine() had a fatal failure. if (HasFatalFailure()) return; // The following won't be executed. ... } ``` If `HasFatalFailure()` is used outside of `TEST()` , `TEST_F()` , or a test fixture, you must add the `::testing::Test::` prefix, as in: ```c++ if (testing::Test::HasFatalFailure()) return; ``` Similarly, `HasNonfatalFailure()` returns `true` if the current test has at least one non-fatal failure, and `HasFailure()` returns `true` if the current test has at least one failure of either kind. ## Logging Additional Information In your test code, you can call `RecordProperty("key", value)` to log additional information, where `value` can be either a string or an `int`. The *last* value recorded for a key will be emitted to the [XML output](#generating-an-xml-report) if you specify one. For example, the test ```c++ TEST_F(WidgetUsageTest, MinAndMaxWidgets) { RecordProperty("MaximumWidgets", ComputeMaxUsage()); RecordProperty("MinimumWidgets", ComputeMinUsage()); } ``` will output XML like this: ```xml ... ... ``` {: .callout .note} > NOTE: > > * `RecordProperty()` is a static member of the `Test` class. Therefore it > needs to be prefixed with `::testing::Test::` if used outside of the > `TEST` body and the test fixture class. > * *`key`* must be a valid XML attribute name, and cannot conflict with the > ones already used by GoogleTest (`name`, `status`, `time`, `classname`, > `type_param`, and `value_param`). > * Calling `RecordProperty()` outside of the lifespan of a test is allowed. > If it's called outside of a test but between a test suite's > `SetUpTestSuite()` and `TearDownTestSuite()` methods, it will be > attributed to the XML element for the test suite. If it's called outside > of all test suites (e.g. in a test environment), it will be attributed to > the top-level XML element. ## Sharing Resources Between Tests in the Same Test Suite GoogleTest creates a new test fixture object for each test in order to make tests independent and easier to debug. However, sometimes tests use resources that are expensive to set up, making the one-copy-per-test model prohibitively expensive. If the tests don't change the resource, there's no harm in their sharing a single resource copy. So, in addition to per-test set-up/tear-down, GoogleTest also supports per-test-suite set-up/tear-down. To use it: 1. In your test fixture class (say `FooTest` ), declare as `static` some member variables to hold the shared resources. 2. Outside your test fixture class (typically just below it), define those member variables, optionally giving them initial values. 3. In the same test fixture class, define a public member function `static void SetUpTestSuite()` (remember not to spell it as **`SetupTestSuite`** with a small `u`!) to set up the shared resources and a `static void TearDownTestSuite()` function to tear them down. That's it! GoogleTest automatically calls `SetUpTestSuite()` before running the *first test* in the `FooTest` test suite (i.e. before creating the first `FooTest` object), and calls `TearDownTestSuite()` after running the *last test* in it (i.e. after deleting the last `FooTest` object). In between, the tests can use the shared resources. Remember that the test order is undefined, so your code can't depend on a test preceding or following another. Also, the tests must either not modify the state of any shared resource, or, if they do modify the state, they must restore the state to its original value before passing control to the next test. Note that `SetUpTestSuite()` may be called multiple times for a test fixture class that has derived classes, so you should not expect code in the function body to be run only once. Also, derived classes still have access to shared resources defined as static members, so careful consideration is needed when managing shared resources to avoid memory leaks if shared resources are not properly cleaned up in `TearDownTestSuite()`. Here's an example of per-test-suite set-up and tear-down: ```c++ class FooTest : public testing::Test { protected: // Per-test-suite set-up. // Called before the first test in this test suite. // Can be omitted if not needed. static void SetUpTestSuite() { shared_resource_ = new ...; // If `shared_resource_` is **not deleted** in `TearDownTestSuite()`, // reallocation should be prevented because `SetUpTestSuite()` may be called // in subclasses of FooTest and lead to memory leak. // // if (shared_resource_ == nullptr) { // shared_resource_ = new ...; // } } // Per-test-suite tear-down. // Called after the last test in this test suite. // Can be omitted if not needed. static void TearDownTestSuite() { delete shared_resource_; shared_resource_ = nullptr; } // You can define per-test set-up logic as usual. void SetUp() override { ... } // You can define per-test tear-down logic as usual. void TearDown() override { ... } // Some expensive resource shared by all tests. static T* shared_resource_; }; T* FooTest::shared_resource_ = nullptr; TEST_F(FooTest, Test1) { ... you can refer to shared_resource_ here ... } TEST_F(FooTest, Test2) { ... you can refer to shared_resource_ here ... } ``` {: .callout .note} NOTE: Though the above code declares `SetUpTestSuite()` protected, it may sometimes be necessary to declare it public, such as when using it with `TEST_P`. ## Global Set-Up and Tear-Down Just as you can do set-up and tear-down at the test level and the test suite level, you can also do it at the test program level. Here's how. First, you subclass the `::testing::Environment` class to define a test environment, which knows how to set-up and tear-down: ```c++ class Environment : public ::testing::Environment { public: ~Environment() override {} // Override this to define how to set up the environment. void SetUp() override {} // Override this to define how to tear down the environment. void TearDown() override {} }; ``` Then, you register an instance of your environment class with GoogleTest by calling the `::testing::AddGlobalTestEnvironment()` function: ```c++ Environment* AddGlobalTestEnvironment(Environment* env); ``` Now, when `RUN_ALL_TESTS()` is invoked, it first calls the `SetUp()` method. The tests are then executed, provided that none of the environments have reported fatal failures and `GTEST_SKIP()` has not been invoked. Finally, `TearDown()` is called. Note that `SetUp()` and `TearDown()` are only invoked if there is at least one test to be performed. Importantly, `TearDown()` is executed even if the test is not run due to a fatal failure or `GTEST_SKIP()`. Calling `SetUp()` and `TearDown()` for each iteration depends on the flag `gtest_recreate_environments_when_repeating`. `SetUp()` and `TearDown()` are called for each environment object when the object is recreated for each iteration. However, if test environments are not recreated for each iteration, `SetUp()` is called only on the first iteration, and `TearDown()` is called only on the last iteration. It's OK to register multiple environment objects. In this suite, their `SetUp()` will be called in the order they are registered, and their `TearDown()` will be called in the reverse order. Note that GoogleTest takes ownership of the registered environment objects. Therefore **do not delete them** by yourself. You should call `AddGlobalTestEnvironment()` before `RUN_ALL_TESTS()` is called, probably in `main()`. If you use `gtest_main`, you need to call this before `main()` starts for it to take effect. One way to do this is to define a global variable like this: ```c++ testing::Environment* const foo_env = testing::AddGlobalTestEnvironment(new FooEnvironment); ``` However, we strongly recommend you to write your own `main()` and call `AddGlobalTestEnvironment()` there, as relying on initialization of global variables makes the code harder to read and may cause problems when you register multiple environments from different translation units and the environments have dependencies among them (remember that the compiler doesn't guarantee the order in which global variables from different translation units are initialized). ## Value-Parameterized Tests *Value-parameterized tests* allow you to test your code with different parameters without writing multiple copies of the same test. This is useful in a number of situations, for example: * You have a piece of code whose behavior is affected by one or more command-line flags. You want to make sure your code performs correctly for various values of those flags. * You want to test different implementations of an OO interface. * You want to test your code over various inputs (a.k.a. data-driven testing). This feature is easy to abuse, so please exercise your good sense when doing it! ### How to Write Value-Parameterized Tests To write value-parameterized tests, first you should define a fixture class. It must be derived from both `testing::Test` and `testing::WithParamInterface` (the latter is a pure interface), where `T` is the type of your parameter values. For convenience, you can just derive the fixture class from `testing::TestWithParam`, which itself is derived from both `testing::Test` and `testing::WithParamInterface`. `T` can be any copyable type. If it's a raw pointer, you are responsible for managing the lifespan of the pointed values. {: .callout .note} NOTE: If your test fixture defines `SetUpTestSuite()` or `TearDownTestSuite()` they must be declared **public** rather than **protected** in order to use `TEST_P`. ```c++ class FooTest : public testing::TestWithParam { // You can implement all the usual fixture class members here. // To access the test parameter, call GetParam() from class // TestWithParam. }; // Or, when you want to add parameters to a pre-existing fixture class: class BaseTest : public testing::Test { ... }; class BarTest : public BaseTest, public testing::WithParamInterface { ... }; ``` Then, use the `TEST_P` macro to define as many test patterns using this fixture as you want. The `_P` suffix is for "parameterized" or "pattern", whichever you prefer to think. ```c++ TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } ``` Finally, you can use the `INSTANTIATE_TEST_SUITE_P` macro to instantiate the test suite with any set of parameters you want. GoogleTest defines a number of functions for generating test parameters—see details at [`INSTANTIATE_TEST_SUITE_P`](reference/testing.md#INSTANTIATE_TEST_SUITE_P) in the Testing Reference. For example, the following statement will instantiate tests from the `FooTest` test suite each with parameter values `"meeny"`, `"miny"`, and `"moe"` using the [`Values`](reference/testing.md#param-generators) parameter generator: ```c++ INSTANTIATE_TEST_SUITE_P(MeenyMinyMoe, FooTest, testing::Values("meeny", "miny", "moe")); ``` {: .callout .note} NOTE: The code above must be placed at global or namespace scope, not at function scope. The first argument to `INSTANTIATE_TEST_SUITE_P` is a unique name for the instantiation of the test suite. The next argument is the name of the test pattern, and the last is the [parameter generator](reference/testing.md#param-generators). The parameter generator expression is not evaluated until GoogleTest is initialized (via `InitGoogleTest()`). Any prior initialization done in the `main` function will be accessible from the parameter generator, for example, the results of flag parsing. You can instantiate a test pattern more than once, so to distinguish different instances of the pattern, the instantiation name is added as a prefix to the actual test suite name. Remember to pick unique prefixes for different instantiations. The tests from the instantiation above will have these names: * `MeenyMinyMoe/FooTest.DoesBlah/0` for `"meeny"` * `MeenyMinyMoe/FooTest.DoesBlah/1` for `"miny"` * `MeenyMinyMoe/FooTest.DoesBlah/2` for `"moe"` * `MeenyMinyMoe/FooTest.HasBlahBlah/0` for `"meeny"` * `MeenyMinyMoe/FooTest.HasBlahBlah/1` for `"miny"` * `MeenyMinyMoe/FooTest.HasBlahBlah/2` for `"moe"` You can use these names in [`--gtest_filter`](#running-a-subset-of-the-tests). The following statement will instantiate all tests from `FooTest` again, each with parameter values `"cat"` and `"dog"` using the [`ValuesIn`](reference/testing.md#param-generators) parameter generator: ```c++ constexpr absl::string_view kPets[] = {"cat", "dog"}; INSTANTIATE_TEST_SUITE_P(Pets, FooTest, testing::ValuesIn(kPets)); ``` The tests from the instantiation above will have these names: * `Pets/FooTest.DoesBlah/0` for `"cat"` * `Pets/FooTest.DoesBlah/1` for `"dog"` * `Pets/FooTest.HasBlahBlah/0` for `"cat"` * `Pets/FooTest.HasBlahBlah/1` for `"dog"` Please note that `INSTANTIATE_TEST_SUITE_P` will instantiate *all* tests in the given test suite, whether their definitions come before or *after* the `INSTANTIATE_TEST_SUITE_P` statement. Additionally, by default, every `TEST_P` without a corresponding `INSTANTIATE_TEST_SUITE_P` causes a failing test in test suite `GoogleTestVerification`. If you have a test suite where that omission is not an error, for example it is in a library that may be linked in for other reasons or where the list of test cases is dynamic and may be empty, then this check can be suppressed by tagging the test suite: ```c++ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FooTest); ``` You can see [sample7_unittest.cc] and [sample8_unittest.cc] for more examples. [sample7_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample7_unittest.cc "Parameterized Test example" [sample8_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample8_unittest.cc "Parameterized Test example with multiple parameters" ### Creating Value-Parameterized Abstract Tests In the above, we define and instantiate `FooTest` in the *same* source file. Sometimes you may want to define value-parameterized tests in a library and let other people instantiate them later. This pattern is known as *abstract tests*. As an example of its application, when you are designing an interface you can write a standard suite of abstract tests (perhaps using a factory function as the test parameter) that all implementations of the interface are expected to pass. When someone implements the interface, they can instantiate your suite to get all the interface-conformance tests for free. To define abstract tests, you should organize your code like this: 1. Put the definition of the parameterized test fixture class (e.g. `FooTest`) in a header file, say `foo_param_test.h`. Think of this as *declaring* your abstract tests. 2. Put the `TEST_P` definitions in `foo_param_test.cc`, which includes `foo_param_test.h`. Think of this as *implementing* your abstract tests. Once they are defined, you can instantiate them by including `foo_param_test.h`, invoking `INSTANTIATE_TEST_SUITE_P()`, and depending on the library target that contains `foo_param_test.cc`. You can instantiate the same abstract test suite multiple times, possibly in different source files. ### Specifying Names for Value-Parameterized Test Parameters The optional last argument to `INSTANTIATE_TEST_SUITE_P()` allows the user to specify a function or functor that generates custom test name suffixes based on the test parameters. The function should accept one argument of type `testing::TestParamInfo`, and return `std::string`. `testing::PrintToStringParamName` is a builtin test suffix generator that returns the value of `testing::PrintToString(GetParam())`. It does not work for `std::string` or C strings. {: .callout .note} NOTE: test names must be non-empty, unique, and may only contain ASCII alphanumeric characters. In particular, they [should not contain underscores](faq.md#why-should-test-suite-names-and-test-names-not-contain-underscore) ```c++ class MyTestSuite : public testing::TestWithParam {}; TEST_P(MyTestSuite, MyTest) { std::cout << "Example Test Param: " << GetParam() << std::endl; } INSTANTIATE_TEST_SUITE_P(MyGroup, MyTestSuite, testing::Range(0, 10), testing::PrintToStringParamName()); ``` Providing a custom functor allows for more control over test parameter name generation, especially for types where the automatic conversion does not generate helpful parameter names (e.g. strings as demonstrated above). The following example illustrates this for multiple parameters, an enumeration type and a string, and also demonstrates how to combine generators. It uses a lambda for conciseness: ```c++ enum class MyType { MY_FOO = 0, MY_BAR = 1 }; class MyTestSuite : public testing::TestWithParam> { }; INSTANTIATE_TEST_SUITE_P( MyGroup, MyTestSuite, testing::Combine( testing::Values(MyType::MY_FOO, MyType::MY_BAR), testing::Values("A", "B")), [](const testing::TestParamInfo& info) { std::string name = absl::StrCat( std::get<0>(info.param) == MyType::MY_FOO ? "Foo" : "Bar", std::get<1>(info.param)); absl::c_replace_if(name, [](char c) { return !std::isalnum(c); }, '_'); return name; }); ``` ## Typed Tests Suppose you have multiple implementations of the same interface and want to make sure that all of them satisfy some common requirements. Or, you may have defined several types that are supposed to conform to the same "concept" and you want to verify it. In both cases, you want the same test logic repeated for different types. While you can write one `TEST` or `TEST_F` for each type you want to test (and you may even factor the test logic into a function template that you invoke from the `TEST`), it's tedious and doesn't scale: if you want `m` tests over `n` types, you'll end up writing `m*n` `TEST`s. *Typed tests* allow you to repeat the same test logic over a list of types. You only need to write the test logic once, although you must know the type list when writing typed tests. Here's how you do it: First, define a fixture class template. It should be parameterized by a type. Remember to derive it from `::testing::Test`: ```c++ template class FooTest : public testing::Test { public: ... using List = std::list; static T shared_; T value_; }; ``` Next, associate a list of types with the test suite, which will be repeated for each type in the list: ```c++ using MyTypes = ::testing::Types; TYPED_TEST_SUITE(FooTest, MyTypes); ``` The type alias (`using` or `typedef`) is necessary for the `TYPED_TEST_SUITE` macro to parse correctly. Otherwise the compiler will think that each comma in the type list introduces a new macro argument. Then, use `TYPED_TEST()` instead of `TEST_F()` to define a typed test for this test suite. You can repeat this as many times as you want: ```c++ TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to the special name TypeParam to get the type // parameter. Since we are inside a derived class template, C++ requires // us to visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the 'TestFixture::' // prefix. n += TestFixture::shared_; // To refer to typedefs in the fixture, add the 'typename TestFixture::' // prefix. The 'typename' is required to satisfy the compiler. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } ``` You can see [sample6_unittest.cc] for a complete example. [sample6_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample6_unittest.cc "Typed Test example" ## Type-Parameterized Tests *Type-parameterized tests* are like typed tests, except that they don't require you to know the list of types ahead of time. Instead, you can define the test logic first and instantiate it with different type lists later. You can even instantiate it more than once in the same program. If you are designing an interface or concept, you can define a suite of type-parameterized tests to verify properties that any valid implementation of the interface/concept should have. Then, the author of each implementation can just instantiate the test suite with their type to verify that it conforms to the requirements, without having to write similar tests repeatedly. Here's an example: First, define a fixture class template, as we did with typed tests: ```c++ template class FooTest : public testing::Test { void DoSomethingInteresting(); ... }; ``` Next, declare that you will define a type-parameterized test suite: ```c++ TYPED_TEST_SUITE_P(FooTest); ``` Then, use `TYPED_TEST_P()` to define a type-parameterized test. You can repeat this as many times as you want: ```c++ TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; // You will need to use `this` explicitly to refer to fixture members. this->DoSomethingInteresting() ... } TYPED_TEST_P(FooTest, HasPropertyA) { ... } ``` Now the tricky part: you need to register all test patterns using the `REGISTER_TYPED_TEST_SUITE_P` macro before you can instantiate them. The first argument of the macro is the test suite name; the rest are the names of the tests in this test suite: ```c++ REGISTER_TYPED_TEST_SUITE_P(FooTest, DoesBlah, HasPropertyA); ``` Finally, you are free to instantiate the pattern with the types you want. If you put the above code in a header file, you can `#include` it in multiple C++ source files and instantiate it multiple times. ```c++ using MyTypes = ::testing::Types; INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); ``` To distinguish different instances of the pattern, the first argument to the `INSTANTIATE_TYPED_TEST_SUITE_P` macro is a prefix that will be added to the actual test suite name. Remember to pick unique prefixes for different instances. In the special case where the type list contains only one type, you can write that type directly without `::testing::Types<...>`, like this: ```c++ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); ``` You can see [sample6_unittest.cc] for a complete example. ## Testing Private Code If you change your software's internal implementation, your tests should not break as long as the change is not observable by users. Therefore, **per the black-box testing principle, most of the time you should test your code through its public interfaces.** **If you still find yourself needing to test internal implementation code, consider if there's a better design.** The desire to test internal implementation is often a sign that the class is doing too much. Consider extracting an implementation class, and testing it. Then use that implementation class in the original class. If you absolutely have to test non-public interface code though, you can. There are two cases to consider: * Static functions ( *not* the same as static member functions!) or unnamed namespaces, and * Private or protected class members To test them, we use the following special techniques: * Both static functions and definitions/declarations in an unnamed namespace are only visible within the same translation unit. To test them, move the private code into the `foo::internal` namespace, where `foo` is the namespace your project normally uses, and put the private declarations in a `*-internal.h` file. Your production `.cc` files and your tests are allowed to include this internal header, but your clients are not. This way, you can fully test your internal implementation without leaking it to your clients. {: .callout .note} NOTE: It is also technically *possible* to `#include` the entire `.cc` file being tested in your `*_test.cc` file to test static functions and definitions/declarations in an unnamed namespace. However, this technique is **not recommended** by this documentation and it is only presented here for the sake of completeness. * Private class members are only accessible from within the class or by friends. To access a class' private members, you can declare your test fixture as a friend to the class and define accessors in your fixture. Tests using the fixture can then access the private members of your production class via the accessors in the fixture. Note that even though your fixture is a friend to your production class, your tests are not automatically friends to it, as they are technically defined in sub-classes of the fixture. Another way to test private members is to refactor them into an implementation class, which is then declared in a `*-internal.h` file. Your clients aren't allowed to include this header but your tests can. Or, you can declare an individual test as a friend of your class by adding this line in the class body: ```c++ FRIEND_TEST(TestSuiteName, TestName); ``` For example, ```c++ // foo.h class Foo { ... private: FRIEND_TEST(FooTest, BarReturnsZeroOnNull); int Bar(void* x); }; // foo_test.cc ... TEST(FooTest, BarReturnsZeroOnNull) { Foo foo; EXPECT_EQ(foo.Bar(NULL), 0); // Uses Foo's private member Bar(). } ``` Pay special attention when your class is defined in a namespace. If you want your test fixtures and tests to be friends of your class, then they must be defined in the exact same namespace (no anonymous or inline namespaces). For example, if the code to be tested looks like: ```c++ namespace my_namespace { class Foo { friend class FooTest; FRIEND_TEST(FooTest, Bar); FRIEND_TEST(FooTest, Baz); ... definition of the class Foo ... }; } // namespace my_namespace ``` Your test code should be something like: ```c++ namespace my_namespace { class FooTest : public testing::Test { protected: ... }; TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } } // namespace my_namespace ``` ## "Catching" Failures If you are building a testing utility on top of GoogleTest, you'll want to test your utility. What framework would you use to test it? GoogleTest, of course. The challenge is to verify that your testing utility reports failures correctly. In frameworks that report a failure by throwing an exception, you could catch the exception and assert on it. But GoogleTest doesn't use exceptions, so how do we test that a piece of code generates an expected failure? `"gtest/gtest-spi.h"` contains some constructs to do this. After #including this header, you can use ```c++ EXPECT_FATAL_FAILURE(statement, substring); ``` to assert that `statement` generates a fatal (e.g. `ASSERT_*`) failure in the current thread whose message contains the given `substring`, or use ```c++ EXPECT_NONFATAL_FAILURE(statement, substring); ``` if you are expecting a non-fatal (e.g. `EXPECT_*`) failure. Only failures in the current thread are checked to determine the result of this type of expectations. If `statement` creates new threads, failures in these threads are also ignored. If you want to catch failures in other threads as well, use one of the following macros instead: ```c++ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substring); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substring); ``` {: .callout .note} NOTE: Assertions from multiple threads are currently not supported on Windows. For technical reasons, there are some caveats: 1. You cannot stream a failure message to either macro. 2. `statement` in `EXPECT_FATAL_FAILURE{_ON_ALL_THREADS}()` cannot reference local non-static variables or non-static members of `this` object. 3. `statement` in `EXPECT_FATAL_FAILURE{_ON_ALL_THREADS}()` cannot return a value. ## Registering tests programmatically The `TEST` macros handle the vast majority of all use cases, but there are few where runtime registration logic is required. For those cases, the framework provides the `::testing::RegisterTest` that allows callers to register arbitrary tests dynamically. This is an advanced API only to be used when the `TEST` macros are insufficient. The macros should be preferred when possible, as they avoid most of the complexity of calling this function. It provides the following signature: ```c++ template TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, const char* type_param, const char* value_param, const char* file, int line, Factory factory); ``` The `factory` argument is a factory callable (move-constructible) object or function pointer that creates a new instance of the Test object. It handles ownership to the caller. The signature of the callable is `Fixture*()`, where `Fixture` is the test fixture class for the test. All tests registered with the same `test_suite_name` must return the same fixture type. This is checked at runtime. The framework will infer the fixture class from the factory and will call the `SetUpTestSuite` and `TearDownTestSuite` for it. Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is undefined. Use case example: ```c++ class MyFixture : public testing::Test { public: // All of these optional, just like in regular macro usage. static void SetUpTestSuite() { ... } static void TearDownTestSuite() { ... } void SetUp() override { ... } void TearDown() override { ... } }; class MyTest : public MyFixture { public: explicit MyTest(int data) : data_(data) {} void TestBody() override { ... } private: int data_; }; void RegisterMyTests(const std::vector& values) { for (int v : values) { testing::RegisterTest( "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, std::to_string(v).c_str(), __FILE__, __LINE__, // Important to use the fixture type as the return type here. [=]() -> MyFixture* { return new MyTest(v); }); } } ... int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); std::vector values_to_test = LoadValuesFromConfig(); RegisterMyTests(values_to_test); ... return RUN_ALL_TESTS(); } ``` ## Getting the Current Test's Name Sometimes a function may need to know the name of the currently running test. For example, you may be using the `SetUp()` method of your test fixture to set the golden file name based on which test is running. The [`TestInfo`](reference/testing.md#TestInfo) class has this information. To obtain a `TestInfo` object for the currently running test, call `current_test_info()` on the [`UnitTest`](reference/testing.md#UnitTest) singleton object: ```c++ // Gets information about the currently running test. // Do NOT delete the returned object - it's managed by the UnitTest class. const testing::TestInfo* const test_info = testing::UnitTest::GetInstance()->current_test_info(); printf("We are in test %s of test suite %s.\n", test_info->name(), test_info->test_suite_name()); ``` `current_test_info()` returns a null pointer if no test is running. In particular, you cannot find the test suite name in `SetUpTestSuite()`, `TearDownTestSuite()` (where you know the test suite name implicitly), or functions called from them. ## Extending GoogleTest by Handling Test Events GoogleTest provides an **event listener API** to let you receive notifications about the progress of a test program and test failures. The events you can listen to include the start and end of the test program, a test suite, or a test method, among others. You may use this API to augment or replace the standard console output, replace the XML output, or provide a completely different form of output, such as a GUI or a database. You can also use test events as checkpoints to implement a resource leak checker, for example. ### Defining Event Listeners To define a event listener, you subclass either [`testing::TestEventListener`](reference/testing.md#TestEventListener) or [`testing::EmptyTestEventListener`](reference/testing.md#EmptyTestEventListener) The former is an (abstract) interface, where *each pure virtual method can be overridden to handle a test event* (For example, when a test starts, the `OnTestStart()` method will be called.). The latter provides an empty implementation of all methods in the interface, such that a subclass only needs to override the methods it cares about. When an event is fired, its context is passed to the handler function as an argument. The following argument types are used: * UnitTest reflects the state of the entire test program, * TestSuite has information about a test suite, which can contain one or more tests, * TestInfo contains the state of a test, and * TestPartResult represents the result of a test assertion. An event handler function can examine the argument it receives to find out interesting information about the event and the test program's state. Here's an example: ```c++ class MinimalistPrinter : public testing::EmptyTestEventListener { // Called before a test starts. void OnTestStart(const testing::TestInfo& test_info) override { printf("*** Test %s.%s starting.\n", test_info.test_suite_name(), test_info.name()); } // Called after a failed assertion or a SUCCESS(). void OnTestPartResult(const testing::TestPartResult& test_part_result) override { printf("%s in %s:%d\n%s\n", test_part_result.failed() ? "*** Failure" : "Success", test_part_result.file_name(), test_part_result.line_number(), test_part_result.summary()); } // Called after a test ends. void OnTestEnd(const testing::TestInfo& test_info) override { printf("*** Test %s.%s ending.\n", test_info.test_suite_name(), test_info.name()); } }; ``` ### Using Event Listeners To use the event listener you have defined, add an instance of it to the GoogleTest event listener list (represented by class [`TestEventListeners`](reference/testing.md#TestEventListeners) - note the "s" at the end of the name) in your `main()` function, before calling `RUN_ALL_TESTS()`: ```c++ int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); // Gets hold of the event listener list. testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); // Adds a listener to the end. GoogleTest takes the ownership. listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); } ``` There's only one problem: the default test result printer is still in effect, so its output will mingle with the output from your minimalist printer. To suppress the default printer, just release it from the event listener list and delete it. You can do so by adding one line: ```c++ ... delete listeners.Release(listeners.default_result_printer()); listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); ``` Now, sit back and enjoy a completely different output from your tests. For more details, see [sample9_unittest.cc]. [sample9_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample9_unittest.cc "Event listener example" You may append more than one listener to the list. When an `On*Start()` or `OnTestPartResult()` event is fired, the listeners will receive it in the order they appear in the list (since new listeners are added to the end of the list, the default text printer and the default XML generator will receive the event first). An `On*End()` event will be received by the listeners in the *reverse* order. This allows output by listeners added later to be framed by output from listeners added earlier. ### Generating Failures in Listeners You may use failure-raising macros (`EXPECT_*()`, `ASSERT_*()`, `FAIL()`, etc) when processing an event. There are some restrictions: 1. You cannot generate any failure in `OnTestPartResult()` (otherwise it will cause `OnTestPartResult()` to be called recursively). 2. A listener that handles `OnTestPartResult()` is not allowed to generate any failure. When you add listeners to the listener list, you should put listeners that handle `OnTestPartResult()` *before* listeners that can generate failures. This ensures that failures generated by the latter are attributed to the right test by the former. See [sample10_unittest.cc] for an example of a failure-raising listener. [sample10_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample10_unittest.cc "Failure-raising listener example" ## Running Test Programs: Advanced Options GoogleTest test programs are ordinary executables. Once built, you can run them directly and affect their behavior via the following environment variables and/or command line flags. For the flags to work, your programs must call `::testing::InitGoogleTest()` before calling `RUN_ALL_TESTS()`. To see a list of supported flags and their usage, please run your test program with the `--help` flag. If an option is specified both by an environment variable and by a flag, the latter takes precedence. ### Selecting Tests #### Listing Test Names Sometimes it is necessary to list the available tests in a program before running them so that a filter may be applied if needed. Including the flag `--gtest_list_tests` overrides all other flags and lists tests in the following format: ```none TestSuite1. TestName1 TestName2 TestSuite2. TestName ``` None of the tests listed are actually run if the flag is provided. There is no corresponding environment variable for this flag. #### Running a Subset of the Tests By default, a GoogleTest program runs all tests the user has defined. Sometimes, you want to run only a subset of the tests (e.g. for debugging or quickly verifying a change). If you set the `GTEST_FILTER` environment variable or the `--gtest_filter` flag to a filter string, GoogleTest will only run the tests whose full names (in the form of `TestSuiteName.TestName`) match the filter. The format of a filter is a '`:`'-separated list of wildcard patterns (called the *positive patterns*) optionally followed by a '`-`' and another '`:`'-separated pattern list (called the *negative patterns*). A test matches the filter if and only if it matches any of the positive patterns but does not match any of the negative patterns. A pattern may contain `'*'` (matches any string) or `'?'` (matches any single character). For convenience, the filter `'*-NegativePatterns'` can be also written as `'-NegativePatterns'`. For example: * `./foo_test` Has no flag, and thus runs all its tests. * `./foo_test --gtest_filter=*` Also runs everything, due to the single match-everything `*` value. * `./foo_test --gtest_filter=FooTest.*` Runs everything in test suite `FooTest` . * `./foo_test --gtest_filter=*Null*:*Constructor*` Runs any test whose full name contains either `"Null"` or `"Constructor"` . * `./foo_test --gtest_filter=-*DeathTest.*` Runs all non-death tests. * `./foo_test --gtest_filter=FooTest.*-FooTest.Bar` Runs everything in test suite `FooTest` except `FooTest.Bar`. * `./foo_test --gtest_filter=FooTest.*:BarTest.*-FooTest.Bar:BarTest.Foo` Runs everything in test suite `FooTest` except `FooTest.Bar` and everything in test suite `BarTest` except `BarTest.Foo`. #### Stop test execution upon first failure By default, a GoogleTest program runs all tests the user has defined. In some cases (e.g. iterative test development & execution) it may be desirable stop test execution upon first failure (trading improved latency for completeness). If `GTEST_FAIL_FAST` environment variable or `--gtest_fail_fast` flag is set, the test runner will stop execution as soon as the first test failure is found. #### Temporarily Disabling Tests If you have a broken test that you cannot fix right away, you can add the `DISABLED_` prefix to its name. This will exclude it from execution. This is better than commenting out the code or using `#if 0`, as disabled tests are still compiled (and thus won't rot). If you need to disable all tests in a test suite, you can either add `DISABLED_` to the front of the name of each test, or alternatively add it to the front of the test suite name. For example, the following tests won't be run by GoogleTest, even though they will still be compiled: ```c++ // Tests that Foo does Abc. TEST(FooTest, DISABLED_DoesAbc) { ... } class DISABLED_BarTest : public testing::Test { ... }; // Tests that Bar does Xyz. TEST_F(DISABLED_BarTest, DoesXyz) { ... } ``` {: .callout .note} NOTE: This feature should only be used for temporary pain-relief. You still have to fix the disabled tests at a later date. As a reminder, GoogleTest will print a banner warning you if a test program contains any disabled tests. {: .callout .tip} TIP: You can easily count the number of disabled tests you have using `grep`. This number can be used as a metric for improving your test quality. #### Temporarily Enabling Disabled Tests To include disabled tests in test execution, just invoke the test program with the `--gtest_also_run_disabled_tests` flag or set the `GTEST_ALSO_RUN_DISABLED_TESTS` environment variable to a value other than `0`. You can combine this with the `--gtest_filter` flag to further select which disabled tests to run. ### Enforcing Having At Least One Test Case A not uncommon programmer mistake is to write a test program that has no test case linked in. This can happen, for example, when you put test case definitions in a library and the library is not marked as "always link". To catch such mistakes, run the test program with the `--gtest_fail_if_no_test_linked` flag or set the `GTEST_FAIL_IF_NO_TEST_LINKED` environment variable to a value other than `0`. Now the program will fail if no test case is linked in. Note that *any* test case linked in makes the program valid for the purpose of this check. In particular, even a disabled test case suffices. ### Enforcing Running At Least One Test Case In addition to enforcing that tests are defined in the binary with `--gtest_fail_if_no_test_linked`, it is also possible to enforce that a test case was actually executed to ensure that resources are not consumed by tests that do nothing. To catch such optimization opportunities, run the test program with the `--gtest_fail_if_no_test_selected` flag or set the `GTEST_FAIL_IF_NO_TEST_SELECTED` environment variable to a value other than `0`. A test is considered selected if it begins to run, even if it is later skipped via `GTEST_SKIP`. Thus, `DISABLED` tests do not count as selected and neither do tests that are not matched by `--gtest_filter`. ### Repeating the Tests Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it will fail only 1% of the time, making it rather hard to reproduce the bug under a debugger. This can be a major source of frustration. The `--gtest_repeat` flag allows you to repeat all (or selected) test methods in a program many times. Hopefully, a flaky test will eventually fail and give you a chance to debug. Here's how to use it: ```none $ foo_test --gtest_repeat=1000 Repeat foo_test 1000 times and don't stop at failures. $ foo_test --gtest_repeat=-1 A negative count means repeating forever. $ foo_test --gtest_repeat=1000 --gtest_break_on_failure Repeat foo_test 1000 times, stopping at the first failure. This is especially useful when running under a debugger: when the test fails, it will drop into the debugger and you can then inspect variables and stacks. $ foo_test --gtest_repeat=1000 --gtest_filter=FooBar.* Repeat the tests whose name matches the filter 1000 times. ``` If your test program contains [global set-up/tear-down](#global-set-up-and-tear-down) code, it will be repeated in each iteration as well, as the flakiness may be in it. To avoid repeating global set-up/tear-down, specify `--gtest_recreate_environments_when_repeating=false`{.nowrap}. You can also specify the repeat count by setting the `GTEST_REPEAT` environment variable. ### Shuffling the Tests You can specify the `--gtest_shuffle` flag (or set the `GTEST_SHUFFLE` environment variable to `1`) to run the tests in a program in a random order. This helps to reveal bad dependencies between tests. By default, GoogleTest uses a random seed calculated from the current time. Therefore you'll get a different order every time. The console output includes the random seed value, such that you can reproduce an order-related test failure later. To specify the random seed explicitly, use the `--gtest_random_seed=SEED` flag (or set the `GTEST_RANDOM_SEED` environment variable), where `SEED` is an integer in the range [0, 99999]. The seed value 0 is special: it tells GoogleTest to do the default behavior of calculating the seed from the current time. If you combine this with `--gtest_repeat=N`, GoogleTest will pick a different random seed and re-shuffle the tests in each iteration. ### Distributing Test Functions to Multiple Machines If you have more than one machine you can use to run a test program, you might want to run the test functions in parallel and get the result faster. We call this technique *sharding*, where each machine is called a *shard*. GoogleTest is compatible with test sharding. To take advantage of this feature, your test runner (not part of GoogleTest) needs to do the following: 1. Allocate a number of machines (shards) to run the tests. 1. On each shard, set the `GTEST_TOTAL_SHARDS` environment variable to the total number of shards. It must be the same for all shards. 1. On each shard, set the `GTEST_SHARD_INDEX` environment variable to the index of the shard. Different shards must be assigned different indices, which must be in the range `[0, GTEST_TOTAL_SHARDS - 1]`. 1. Run the same test program on all shards. When GoogleTest sees the above two environment variables, it will select a subset of the test functions to run. Across all shards, each test function in the program will be run exactly once. 1. Wait for all shards to finish, then collect and report the results. Your project may have tests that were written without GoogleTest and thus don't understand this protocol. In order for your test runner to figure out which test supports sharding, it can set the environment variable `GTEST_SHARD_STATUS_FILE` to a non-existent file path. If a test program supports sharding, it will create this file to acknowledge that fact; otherwise it will not create it. The actual contents of the file are not important at this time, although we may put some useful information in it in the future. Here's an example to make it clear. Suppose you have a test program `foo_test` that contains the following 5 test functions: ``` TEST(A, V) TEST(A, W) TEST(B, X) TEST(B, Y) TEST(B, Z) ``` Suppose you have 3 machines at your disposal. To run the test functions in parallel, you would set `GTEST_TOTAL_SHARDS` to 3 on all machines, and set `GTEST_SHARD_INDEX` to 0, 1, and 2 on the machines respectively. Then you would run the same `foo_test` on each machine. GoogleTest reserves the right to change how the work is distributed across the shards, but here's one possible scenario: * Machine #0 runs `A.V` and `B.X`. * Machine #1 runs `A.W` and `B.Y`. * Machine #2 runs `B.Z`. ### Controlling Test Output #### Colored Terminal Output GoogleTest can use colors in its terminal output to make it easier to spot the important information:
...
[----------] 1 test from FooTest
[ RUN      ] FooTest.DoesAbc
[       OK ] FooTest.DoesAbc
[----------] 2 tests from BarTest
[ RUN      ] BarTest.HasXyzProperty
[       OK ] BarTest.HasXyzProperty
[ RUN      ] BarTest.ReturnsTrueOnSuccess
... some error messages ...
[   FAILED ] BarTest.ReturnsTrueOnSuccess
...
[==========] 30 tests from 14 test suites ran.
[   PASSED ] 28 tests.
[   FAILED ] 2 tests, listed below:
[   FAILED ] BarTest.ReturnsTrueOnSuccess
[   FAILED ] AnotherTest.DoesXyz

 2 FAILED TESTS
You can set the `GTEST_COLOR` environment variable or the `--gtest_color` command line flag to `yes`, `no`, or `auto` (the default) to enable colors, disable colors, or let GoogleTest decide. When the value is `auto`, GoogleTest will use colors if and only if the output goes to a terminal and (on non-Windows platforms) the `TERM` environment variable is set to `xterm` or `xterm-color`. #### Suppressing test passes By default, GoogleTest prints 1 line of output for each test, indicating if it passed or failed. To show only test failures, run the test program with `--gtest_brief=1`, or set the GTEST_BRIEF environment variable to `1`. #### Suppressing the Elapsed Time By default, GoogleTest prints the time it takes to run each test. To disable that, run the test program with the `--gtest_print_time=0` command line flag, or set the GTEST_PRINT_TIME environment variable to `0`. #### Suppressing UTF-8 Text Output In case of assertion failures, GoogleTest prints expected and actual values of type `string` both as hex-encoded strings as well as in readable UTF-8 text if they contain valid non-ASCII UTF-8 characters. If you want to suppress the UTF-8 text because, for example, you don't have an UTF-8 compatible output medium, run the test program with `--gtest_print_utf8=0` or set the `GTEST_PRINT_UTF8` environment variable to `0`. #### Generating an XML Report GoogleTest can emit a detailed XML report to a file in addition to its normal textual output. The report contains the duration of each test, and thus can help you identify slow tests. To generate the XML report, set the `GTEST_OUTPUT` environment variable or the `--gtest_output` flag to the string `"xml:path_to_output_file"`, which will create the file at the given location. You can also just use the string `"xml"`, in which case the output can be found in the `test_detail.xml` file in the current directory. If you specify a directory (for example, `"xml:output/directory/"` on Linux or `"xml:output\directory\"` on Windows), GoogleTest will create the XML file in that directory, named after the test executable (e.g. `foo_test.xml` for test program `foo_test` or `foo_test.exe`). If the file already exists (perhaps left over from a previous run), GoogleTest will pick a different name (e.g. `foo_test_1.xml`) to avoid overwriting it. The report is based on the `junitreport` Ant task. Since that format was originally intended for Java, a little interpretation is required to make it apply to GoogleTest tests, as shown here: ```xml ``` * The root `` element corresponds to the entire test program. * `` elements correspond to GoogleTest test suites. * `` elements correspond to GoogleTest test functions. For instance, the following program ```c++ TEST(MathTest, Addition) { ... } TEST(MathTest, Subtraction) { ... } TEST(LogicTest, NonContradiction) { ... } ``` could generate this report: ```xml ... ... ``` Things to note: * The `tests` attribute of a `` or `` element tells how many test functions the GoogleTest program or test suite contains, while the `failures` attribute tells how many of them failed. * The `time` attribute expresses the duration of the test, test suite, or entire test program in seconds. * The `timestamp` attribute records the local date and time of the test execution. * The `file` and `line` attributes record the source file location, where the test was defined. * Each `` element corresponds to a single failed GoogleTest assertion. #### Generating a JSON Report GoogleTest can also emit a JSON report as an alternative format to XML. To generate the JSON report, set the `GTEST_OUTPUT` environment variable or the `--gtest_output` flag to the string `"json:path_to_output_file"`, which will create the file at the given location. You can also just use the string `"json"`, in which case the output can be found in the `test_detail.json` file in the current directory. The report format conforms to the following JSON Schema: ```json { "$schema": "https://json-schema.org/schema#", "type": "object", "definitions": { "TestCase": { "type": "object", "properties": { "name": { "type": "string" }, "tests": { "type": "integer" }, "failures": { "type": "integer" }, "disabled": { "type": "integer" }, "time": { "type": "string" }, "testsuite": { "type": "array", "items": { "$ref": "#/definitions/TestInfo" } } } }, "TestInfo": { "type": "object", "properties": { "name": { "type": "string" }, "file": { "type": "string" }, "line": { "type": "integer" }, "status": { "type": "string", "enum": ["RUN", "NOTRUN"] }, "time": { "type": "string" }, "classname": { "type": "string" }, "failures": { "type": "array", "items": { "$ref": "#/definitions/Failure" } } } }, "Failure": { "type": "object", "properties": { "failures": { "type": "string" }, "type": { "type": "string" } } } }, "properties": { "tests": { "type": "integer" }, "failures": { "type": "integer" }, "disabled": { "type": "integer" }, "errors": { "type": "integer" }, "timestamp": { "type": "string", "format": "date-time" }, "time": { "type": "string" }, "name": { "type": "string" }, "testsuites": { "type": "array", "items": { "$ref": "#/definitions/TestCase" } } } } ``` The report uses the format that conforms to the following Proto3 using the [JSON encoding](https://developers.google.com/protocol-buffers/docs/proto3#json): ```proto syntax = "proto3"; package googletest; import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; message UnitTest { int32 tests = 1; int32 failures = 2; int32 disabled = 3; int32 errors = 4; google.protobuf.Timestamp timestamp = 5; google.protobuf.Duration time = 6; string name = 7; repeated TestCase testsuites = 8; } message TestCase { string name = 1; int32 tests = 2; int32 failures = 3; int32 disabled = 4; int32 errors = 5; google.protobuf.Duration time = 6; repeated TestInfo testsuite = 7; } message TestInfo { string name = 1; string file = 6; int32 line = 7; enum Status { RUN = 0; NOTRUN = 1; } Status status = 2; google.protobuf.Duration time = 3; string classname = 4; message Failure { string failures = 1; string type = 2; } repeated Failure failures = 5; } ``` For instance, the following program ```c++ TEST(MathTest, Addition) { ... } TEST(MathTest, Subtraction) { ... } TEST(LogicTest, NonContradiction) { ... } ``` could generate this report: ```json { "tests": 3, "failures": 1, "errors": 0, "time": "0.035s", "timestamp": "2011-10-31T18:52:42Z", "name": "AllTests", "testsuites": [ { "name": "MathTest", "tests": 2, "failures": 1, "errors": 0, "time": "0.015s", "testsuite": [ { "name": "Addition", "file": "test.cpp", "line": 1, "status": "RUN", "time": "0.007s", "classname": "", "failures": [ { "message": "Value of: add(1, 1)\n Actual: 3\nExpected: 2", "type": "" }, { "message": "Value of: add(1, -1)\n Actual: 1\nExpected: 0", "type": "" } ] }, { "name": "Subtraction", "file": "test.cpp", "line": 2, "status": "RUN", "time": "0.005s", "classname": "" } ] }, { "name": "LogicTest", "tests": 1, "failures": 0, "errors": 0, "time": "0.005s", "testsuite": [ { "name": "NonContradiction", "file": "test.cpp", "line": 3, "status": "RUN", "time": "0.005s", "classname": "" } ] } ] } ``` {: .callout .important} IMPORTANT: The exact format of the JSON document is subject to change. ### Controlling How Failures Are Reported #### Detecting Test Premature Exit Google Test implements the *premature-exit-file* protocol for test runners to catch any kind of unexpected exits of test programs. Upon start, Google Test creates the file which will be automatically deleted after all work has been finished. Then, the test runner can check if this file exists. In case the file remains undeleted, the inspected test has exited prematurely. This feature is enabled only if the `TEST_PREMATURE_EXIT_FILE` environment variable has been set. #### Turning Assertion Failures into Break-Points When running test programs under a debugger, it's very convenient if the debugger can catch an assertion failure and automatically drop into interactive mode. GoogleTest's *break-on-failure* mode supports this behavior. To enable it, set the `GTEST_BREAK_ON_FAILURE` environment variable to a value other than `0`. Alternatively, you can use the `--gtest_break_on_failure` command line flag. #### Disabling Catching Test-Thrown Exceptions GoogleTest can be used either with or without exceptions enabled. If a test throws a C++ exception or (on Windows) a structured exception (SEH), by default GoogleTest catches it, reports it as a test failure, and continues with the next test method. This maximizes the coverage of a test run. Also, on Windows an uncaught exception will cause a pop-up window, so catching the exceptions allows you to run the tests automatically. When debugging the test failures, however, you may instead want the exceptions to be handled by the debugger, such that you can examine the call stack when an exception is thrown. To achieve that, set the `GTEST_CATCH_EXCEPTIONS` environment variable to `0`, or use the `--gtest_catch_exceptions=0` flag when running the tests. ### Sanitizer Integration The [Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html), [Address Sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer), and [Thread Sanitizer](https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual) all provide weak functions that you can override to trigger explicit failures when they detect sanitizer errors, such as creating a reference from `nullptr`. To override these functions, place definitions for them in a source file that you compile as part of your main binary: ``` extern "C" { void __ubsan_on_report() { FAIL() << "Encountered an undefined behavior sanitizer error"; } void __asan_on_error() { FAIL() << "Encountered an address sanitizer error"; } void __tsan_on_report() { FAIL() << "Encountered a thread sanitizer error"; } } // extern "C" ``` After compiling your project with one of the sanitizers enabled, if a particular test triggers a sanitizer error, GoogleTest will report that it failed. gperftools-gperftools-2.18/vendor/googletest/docs/assets/000077500000000000000000000000001513545575200237315ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/docs/assets/css/000077500000000000000000000000001513545575200245215ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/docs/assets/css/style.scss000066400000000000000000000000701513545575200265530ustar00rootroot00000000000000--- --- @import "jekyll-theme-primer"; @import "main"; gperftools-gperftools-2.18/vendor/googletest/docs/community_created_documentation.md000066400000000000000000000005261513545575200314200ustar00rootroot00000000000000# Community-Created Documentation The following is a list, in no particular order, of links to documentation created by the Googletest community. * [Googlemock Insights](https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/googletest/insights.md), by [ElectricRCAircraftGuy](https://github.com/ElectricRCAircraftGuy) gperftools-gperftools-2.18/vendor/googletest/docs/faq.md000066400000000000000000000670701513545575200235320ustar00rootroot00000000000000# GoogleTest FAQ ## Why should test suite names and test names not contain underscore? {: .callout .note} Note: GoogleTest reserves underscore (`_`) for special-purpose keywords, such as [the `DISABLED_` prefix](advanced.md#temporarily-disabling-tests), in addition to the following rationale. Underscore (`_`) is special, as C++ reserves the following to be used by the compiler and the standard library: 1. any identifier that starts with an `_` followed by an upper-case letter, and 2. any identifier that contains two consecutive underscores (i.e. `__`) *anywhere* in its name. User code is *prohibited* from using such identifiers. Now let's look at what this means for `TEST` and `TEST_F`. Currently `TEST(TestSuiteName, TestName)` generates a class named `TestSuiteName_TestName_Test`. What happens if `TestSuiteName` or `TestName` contains `_`? 1. If `TestSuiteName` starts with an `_` followed by an upper-case letter (say, `_Foo`), we end up with `_Foo_TestName_Test`, which is reserved and thus invalid. 2. If `TestSuiteName` ends with an `_` (say, `Foo_`), we get `Foo__TestName_Test`, which is invalid. 3. If `TestName` starts with an `_` (say, `_Bar`), we get `TestSuiteName__Bar_Test`, which is invalid. 4. If `TestName` ends with an `_` (say, `Bar_`), we get `TestSuiteName_Bar__Test`, which is invalid. So clearly `TestSuiteName` and `TestName` cannot start or end with `_` (Actually, `TestSuiteName` can start with `_`—as long as the `_` isn't followed by an upper-case letter. But that's getting complicated. So for simplicity we just say that it cannot start with `_`.). It may seem fine for `TestSuiteName` and `TestName` to contain `_` in the middle. However, consider this: ```c++ TEST(Time, Flies_Like_An_Arrow) { ... } TEST(Time_Flies, Like_An_Arrow) { ... } ``` Now, the two `TEST`s will both generate the same class (`Time_Flies_Like_An_Arrow_Test`). That's not good. So for simplicity, we just ask the users to avoid `_` in `TestSuiteName` and `TestName`. The rule is more constraining than necessary, but it's simple and easy to remember. It also gives GoogleTest some wiggle room in case its implementation needs to change in the future. If you violate the rule, there may not be immediate consequences, but your test may (just may) break with a new compiler (or a new version of the compiler you are using) or with a new version of GoogleTest. Therefore it's best to follow the rule. ## Why does GoogleTest support `EXPECT_EQ(NULL, ptr)` and `ASSERT_EQ(NULL, ptr)` but not `EXPECT_NE(NULL, ptr)` and `ASSERT_NE(NULL, ptr)`? First of all, you can use `nullptr` with each of these macros, e.g. `EXPECT_EQ(ptr, nullptr)`, `EXPECT_NE(ptr, nullptr)`, `ASSERT_EQ(ptr, nullptr)`, `ASSERT_NE(ptr, nullptr)`. This is the preferred syntax in the style guide because `nullptr` does not have the type problems that `NULL` does. Due to some peculiarity of C++, it requires some non-trivial template meta programming tricks to support using `NULL` as an argument of the `EXPECT_XX()` and `ASSERT_XX()` macros. Therefore we only do it where it's most needed (otherwise we make the implementation of GoogleTest harder to maintain and more error-prone than necessary). Historically, the `EXPECT_EQ()` macro took the *expected* value as its first argument and the *actual* value as the second, though this argument order is now discouraged. It was reasonable that someone wanted to write `EXPECT_EQ(NULL, some_expression)`, and this indeed was requested several times. Therefore we implemented it. The need for `EXPECT_NE(NULL, ptr)` wasn't nearly as strong. When the assertion fails, you already know that `ptr` must be `NULL`, so it doesn't add any information to print `ptr` in this case. That means `EXPECT_TRUE(ptr != NULL)` works just as well. If we were to support `EXPECT_NE(NULL, ptr)`, for consistency we'd have to support `EXPECT_NE(ptr, NULL)` as well. This means using the template meta programming tricks twice in the implementation, making it even harder to understand and maintain. We believe the benefit doesn't justify the cost. Finally, with the growth of the gMock matcher library, we are encouraging people to use the unified `EXPECT_THAT(value, matcher)` syntax more often in tests. One significant advantage of the matcher approach is that matchers can be easily combined to form new matchers, while the `EXPECT_NE`, etc, macros cannot be easily combined. Therefore we want to invest more in the matchers than in the `EXPECT_XX()` macros. ## I need to test that different implementations of an interface satisfy some common requirements. Should I use typed tests or value-parameterized tests? For testing various implementations of the same interface, either typed tests or value-parameterized tests can get it done. It's really up to you the user to decide which is more convenient for you, depending on your particular case. Some rough guidelines: * Typed tests can be easier to write if instances of the different implementations can be created the same way, modulo the type. For example, if all these implementations have a public default constructor (such that you can write `new TypeParam`), or if their factory functions have the same form (e.g. `CreateInstance()`). * Value-parameterized tests can be easier to write if you need different code patterns to create different implementations' instances, e.g. `new Foo` vs `new Bar(5)`. To accommodate for the differences, you can write factory function wrappers and pass these function pointers to the tests as their parameters. * When a typed test fails, the default output includes the name of the type, which can help you quickly identify which implementation is wrong. Value-parameterized tests only show the number of the failed iteration by default. You will need to define a function that returns the iteration name and pass it as the third parameter to INSTANTIATE_TEST_SUITE_P to have more useful output. * When using typed tests, you need to make sure you are testing against the interface type, not the concrete types (in other words, you want to make sure `implicit_cast(my_concrete_impl)` works, not just that `my_concrete_impl` works). It's less likely to make mistakes in this area when using value-parameterized tests. I hope I didn't confuse you more. :-) If you don't mind, I'd suggest you to give both approaches a try. Practice is a much better way to grasp the subtle differences between the two tools. Once you have some concrete experience, you can much more easily decide which one to use the next time. ## My death test modifies some state, but the change seems lost after the death test finishes. Why? Death tests (`EXPECT_DEATH`, etc.) are executed in a sub-process s.t. the expected crash won't kill the test program (i.e. the parent process). As a result, any in-memory side effects they incur are observable in their respective sub-processes, but not in the parent process. You can think of them as running in a parallel universe, more or less. In particular, if you use mocking and the death test statement invokes some mock methods, the parent process will think the calls have never occurred. Therefore, you may want to move your `EXPECT_CALL` statements inside the `EXPECT_DEATH` macro. ## EXPECT_EQ(htonl(blah), blah_blah) generates weird compiler errors in opt mode. Is this a GoogleTest bug? Actually, the bug is in `htonl()`. According to `'man htonl'`, `htonl()` is a *function*, which means it's valid to use `htonl` as a function pointer. However, in opt mode `htonl()` is defined as a *macro*, which breaks this usage. Worse, the macro definition of `htonl()` uses a `gcc` extension and is *not* standard C++. That hacky implementation has some ad hoc limitations. In particular, it prevents you from writing `Foo()`, where `Foo` is a template that has an integral argument. The implementation of `EXPECT_EQ(a, b)` uses `sizeof(... a ...)` inside a template argument, and thus doesn't compile in opt mode when `a` contains a call to `htonl()`. It is difficult to make `EXPECT_EQ` bypass the `htonl()` bug, as the solution must work with different compilers on various platforms. ## The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body. What's wrong? If your class has a static data member: ```c++ // foo.h class Foo { ... static const int kBar = 100; }; ``` you also need to define it *outside* of the class body in `foo.cc`: ```c++ const int Foo::kBar; // No initializer here. ``` Otherwise your code is **invalid C++**, and may break in unexpected ways. In particular, using it in GoogleTest comparison assertions (`EXPECT_EQ`, etc.) will generate an "undefined reference" linker error. The fact that "it used to work" doesn't mean it's valid. It just means that you were lucky. :-) If the declaration of the static data member is `constexpr` then it is implicitly an `inline` definition, and a separate definition in `foo.cc` is not needed: ```c++ // foo.h class Foo { ... static constexpr int kBar = 100; // Defines kBar, no need to do it in foo.cc. }; ``` ## Can I derive a test fixture from another? Yes. Each test fixture has a corresponding and same named test suite. This means only one test suite can use a particular fixture. Sometimes, however, multiple test cases may want to use the same or slightly different fixtures. For example, you may want to make sure that all of a GUI library's test suites don't leak important system resources like fonts and brushes. In GoogleTest, you share a fixture among test suites by putting the shared logic in a base test fixture, then deriving from that base a separate fixture for each test suite that wants to use this common logic. You then use `TEST_F()` to write tests using each derived fixture. Typically, your code looks like this: ```c++ // Defines a base test fixture. class BaseTest : public ::testing::Test { protected: ... }; // Derives a fixture FooTest from BaseTest. class FooTest : public BaseTest { protected: void SetUp() override { BaseTest::SetUp(); // Sets up the base fixture first. ... additional set-up work ... } void TearDown() override { ... clean-up work for FooTest ... BaseTest::TearDown(); // Remember to tear down the base fixture // after cleaning up FooTest! } ... functions and variables for FooTest ... }; // Tests that use the fixture FooTest. TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } ... additional fixtures derived from BaseTest ... ``` If necessary, you can continue to derive test fixtures from a derived fixture. GoogleTest has no limit on how deep the hierarchy can be. For a complete example using derived test fixtures, see [sample5_unittest.cc](https://github.com/google/googletest/blob/main/googletest/samples/sample5_unittest.cc). ## My compiler complains "void value not ignored as it ought to be." What does this mean? You're probably using an `ASSERT_*()` in a function that doesn't return `void`. `ASSERT_*()` can only be used in `void` functions, due to exceptions being disabled by our build system. Please see more details [here](advanced.md#assertion-placement). ## My death test hangs (or seg-faults). How do I fix it? In GoogleTest, death tests are run in a child process and the way they work is delicate. To write death tests you really need to understand how they work—see the details at [Death Assertions](reference/assertions.md#death) in the Assertions Reference. In particular, death tests don't like having multiple threads in the parent process. So the first thing you can try is to eliminate creating threads outside of `EXPECT_DEATH()`. For example, you may want to use mocks or fake objects instead of real ones in your tests. Sometimes this is impossible as some library you must use may be creating threads before `main()` is even reached. In this case, you can try to minimize the chance of conflicts by either moving as many activities as possible inside `EXPECT_DEATH()` (in the extreme case, you want to move everything inside), or leaving as few things as possible in it. Also, you can try to set the death test style to `"threadsafe"`, which is safer but slower, and see if it helps. If you go with thread-safe death tests, remember that they rerun the test program from the beginning in the child process. Therefore make sure your program can run side-by-side with itself and is deterministic. In the end, this boils down to good concurrent programming. You have to make sure that there are no race conditions or deadlocks in your program. No silver bullet - sorry! ## Should I use the constructor/destructor of the test fixture or SetUp()/TearDown()? {#CtorVsSetUp} The first thing to remember is that GoogleTest does **not** reuse the same test fixture object across multiple tests. For each `TEST_F`, GoogleTest will create a **fresh** test fixture object, immediately call `SetUp()`, run the test body, call `TearDown()`, and then delete the test fixture object. When you need to write per-test set-up and tear-down logic, you have the choice between using the test fixture constructor/destructor or `SetUp()`/`TearDown()`. The former is usually preferred, as it has the following benefits: * By initializing a member variable in the constructor, we have the option to make it `const`, which helps prevent accidental changes to its value and makes the tests more obviously correct. * In case we need to subclass the test fixture class, the subclass' constructor is guaranteed to call the base class' constructor *first*, and the subclass' destructor is guaranteed to call the base class' destructor *afterward*. With `SetUp()/TearDown()`, a subclass may make the mistake of forgetting to call the base class' `SetUp()/TearDown()` or call them at the wrong time. You may still want to use `SetUp()/TearDown()` in the following cases: * C++ does not allow virtual function calls in constructors and destructors. You can call a method declared as virtual, but it will not use dynamic dispatch. It will use the definition from the class the constructor of which is currently executing. This is because calling a virtual method before the derived class constructor has a chance to run is very dangerous - the virtual method might operate on uninitialized data. Therefore, if you need to call a method that will be overridden in a derived class, you have to use `SetUp()/TearDown()`. * In the body of a constructor (or destructor), it's not possible to use the `ASSERT_xx` macros. Therefore, if the set-up operation could cause a fatal test failure that should prevent the test from running, it's necessary to use `abort` and abort the whole test executable, or to use `SetUp()` instead of a constructor. * If the tear-down operation could throw an exception, you must use `TearDown()` as opposed to the destructor, as throwing in a destructor leads to undefined behavior and usually will kill your program right away. Note that many standard libraries (like STL) may throw when exceptions are enabled in the compiler. Therefore you should prefer `TearDown()` if you want to write portable tests that work with or without exceptions. * The GoogleTest team is considering making the assertion macros throw on platforms where exceptions are enabled (e.g. Windows, Mac OS, and Linux client-side), which will eliminate the need for the user to propagate failures from a subroutine to its caller. Therefore, you shouldn't use GoogleTest assertions in a destructor if your code could run on such a platform. ## The compiler complains "no matching function to call" when I use `ASSERT_PRED*`. How do I fix it? See details for [`EXPECT_PRED*`](reference/assertions.md#EXPECT_PRED) in the Assertions Reference. ## My compiler complains about "ignoring return value" when I call RUN_ALL_TESTS(). Why? Some people had been ignoring the return value of `RUN_ALL_TESTS()`. That is, instead of ```c++ return RUN_ALL_TESTS(); ``` they write ```c++ RUN_ALL_TESTS(); ``` This is **wrong and dangerous**. The testing services needs to see the return value of `RUN_ALL_TESTS()` in order to determine if a test has passed. If your `main()` function ignores it, your test will be considered successful even if it has a GoogleTest assertion failure. Very bad. We have decided to fix this (thanks to Michael Chastain for the idea). Now, your code will no longer be able to ignore `RUN_ALL_TESTS()` when compiled with `gcc`. If you do so, you'll get a compiler error. If you see the compiler complaining about you ignoring the return value of `RUN_ALL_TESTS()`, the fix is simple: just make sure its value is used as the return value of `main()`. But how could we introduce a change that breaks existing tests? Well, in this case, the code was already broken in the first place, so we didn't break it. :-) ## My compiler complains that a constructor (or destructor) cannot return a value. What's going on? Due to a peculiarity of C++, in order to support the syntax for streaming messages to an `ASSERT_*`, e.g. ```c++ ASSERT_EQ(1, Foo()) << "blah blah" << foo; ``` we had to give up using `ASSERT*` and `FAIL*` (but not `EXPECT*` and `ADD_FAILURE*`) in constructors and destructors. The workaround is to move the content of your constructor/destructor to a private void member function, or switch to `EXPECT_*()` if that works. This [section](advanced.md#assertion-placement) in the user's guide explains it. ## My SetUp() function is not called. Why? C++ is case-sensitive. Did you spell it as `Setup()`? Similarly, sometimes people spell `SetUpTestSuite()` as `SetupTestSuite()` and wonder why it's never called. ## I have several test suites which share the same test fixture logic; do I have to define a new test fixture class for each of them? This seems pretty tedious. You don't have to. Instead of ```c++ class FooTest : public BaseTest {}; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } class BarTest : public BaseTest {}; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` you can simply `typedef` the test fixtures: ```c++ typedef BaseTest FooTest; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef BaseTest BarTest; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` ## GoogleTest output is buried in a whole bunch of LOG messages. What do I do? The GoogleTest output is meant to be a concise and human-friendly report. If your test generates textual output itself, it will mix with the GoogleTest output, making it hard to read. However, there is an easy solution to this problem. Since `LOG` messages go to stderr, we decided to let GoogleTest output go to stdout. This way, you can easily separate the two using redirection. For example: ```shell $ ./my_test > gtest_output.txt ``` ## Why should I prefer test fixtures over global variables? There are several good reasons: 1. It's likely your test needs to change the states of its global variables. This makes it difficult to keep side effects from escaping one test and contaminating others, making debugging difficult. By using fixtures, each test has a fresh set of variables that's different (but with the same names). Thus, tests are kept independent of each other. 2. Global variables pollute the global namespace. 3. Test fixtures can be reused via subclassing, which cannot be done easily with global variables. This is useful if many test suites have something in common. ## What can the statement argument in ASSERT_DEATH() be? `ASSERT_DEATH(statement, matcher)` (or any death assertion macro) can be used wherever *`statement`* is valid. So basically *`statement`* can be any C++ statement that makes sense in the current context. In particular, it can reference global and/or local variables, and can be: * a simple function call (often the case), * a complex expression, or * a compound statement. Some examples are shown here: ```c++ // A death test can be a simple function call. TEST(MyDeathTest, FunctionCall) { ASSERT_DEATH(Xyz(5), "Xyz failed"); } // Or a complex expression that references variables and functions. TEST(MyDeathTest, ComplexExpression) { const bool c = Condition(); ASSERT_DEATH((c ? Func1(0) : object2.Method("test")), "(Func1|Method) failed"); } // Death assertions can be used anywhere in a function. In // particular, they can be inside a loop. TEST(MyDeathTest, InsideLoop) { // Verifies that Foo(0), Foo(1), ..., and Foo(4) all die. for (int i = 0; i < 5; i++) { EXPECT_DEATH_M(Foo(i), "Foo has \\d+ errors", ::testing::Message() << "where i is " << i); } } // A death assertion can contain a compound statement. TEST(MyDeathTest, CompoundStatement) { // Verifies that at lease one of Bar(0), Bar(1), ..., and // Bar(4) dies. ASSERT_DEATH({ for (int i = 0; i < 5; i++) { Bar(i); } }, "Bar has \\d+ errors"); } ``` ## I have a fixture class `FooTest`, but `TEST_F(FooTest, Bar)` gives me error ``"no matching function for call to `FooTest::FooTest()'"``. Why? GoogleTest needs to be able to create objects of your test fixture class, so it must have a default constructor. Normally the compiler will define one for you. However, there are cases where you have to define your own: * If you explicitly declare a non-default constructor for class `FooTest` (`DISALLOW_EVIL_CONSTRUCTORS()` does this), then you need to define a default constructor, even if it would be empty. * If `FooTest` has a const non-static data member, then you have to define the default constructor *and* initialize the const member in the initializer list of the constructor. (Early versions of `gcc` doesn't force you to initialize the const member. It's a bug that has been fixed in `gcc 4`.) ## Why does GoogleTest require the entire test suite, instead of individual tests, to be named `*DeathTest` when it uses `ASSERT_DEATH`? GoogleTest does not interleave tests from different test suites. That is, it runs all tests in one test suite first, and then runs all tests in the next test suite, and so on. GoogleTest does this because it needs to set up a test suite before the first test in it is run, and tear it down afterwards. Splitting up the test case would require multiple set-up and tear-down processes, which is inefficient and makes the semantics unclean. If we were to determine the order of tests based on test name instead of test case name, then we would have a problem with the following situation: ```c++ TEST_F(FooTest, AbcDeathTest) { ... } TEST_F(FooTest, Uvw) { ... } TEST_F(BarTest, DefDeathTest) { ... } TEST_F(BarTest, Xyz) { ... } ``` Since `FooTest.AbcDeathTest` needs to run before `BarTest.Xyz`, and we don't interleave tests from different test suites, we need to run all tests in the `FooTest` case before running any test in the `BarTest` case. This contradicts with the requirement to run `BarTest.DefDeathTest` before `FooTest.Uvw`. ## But I don't like calling my entire test suite `*DeathTest` when it contains both death tests and non-death tests. What do I do? You don't have to, but if you like, you may split up the test suite into `FooTest` and `FooDeathTest`, where the names make it clear that they are related: ```c++ class FooTest : public ::testing::Test { ... }; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } using FooDeathTest = FooTest; TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... } TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... } ``` ## GoogleTest prints the LOG messages in a death test's child process only when the test fails. How can I see the LOG messages when the death test succeeds? Printing the LOG messages generated by the statement inside `EXPECT_DEATH()` makes it harder to search for real problems in the parent's log. Therefore, GoogleTest only prints them when the death test has failed. If you really need to see such LOG messages, a workaround is to temporarily break the death test (e.g. by changing the regex pattern it is expected to match). Admittedly, this is a hack. We'll consider a more permanent solution after the fork-and-exec-style death tests are implemented. ## The compiler complains about `no match for 'operator<<'` when I use an assertion. What gives? If you use a user-defined type `FooType` in an assertion, you must make sure there is an `std::ostream& operator<<(std::ostream&, const FooType&)` function defined such that we can print a value of `FooType`. In addition, if `FooType` is declared in a name space, the `<<` operator also needs to be defined in the *same* name space. See [Tip of the Week #49](https://abseil.io/tips/49) for details. ## How do I suppress the memory leak messages on Windows? Since the statically initialized GoogleTest singleton requires allocations on the heap, the Visual C++ memory leak detector will report memory leaks at the end of the program run. The easiest way to avoid this is to use the `_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any statically initialized heap objects. See MSDN for more details and additional heap check/debug routines. ## How can my code detect if it is running in a test? If you write code that sniffs whether it's running in a test and does different things accordingly, you are leaking test-only logic into production code and there is no easy way to ensure that the test-only code paths aren't run by mistake in production. Such cleverness also leads to [Heisenbugs](https://en.wikipedia.org/wiki/Heisenbug). Therefore we strongly advise against the practice, and GoogleTest doesn't provide a way to do it. In general, the recommended way to cause the code to behave differently under test is [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection). You can inject different functionality from the test and from the production code. Since your production code doesn't link in the for-test logic at all (the [`testonly`](https://docs.bazel.build/versions/master/be/common-definitions.html#common.testonly) attribute for BUILD targets helps to ensure that), there is no danger in accidentally running it. However, if you *really*, *really*, *really* have no choice, and if you follow the rule of ending your test program names with `_test`, you can use the *horrible* hack of sniffing your executable name (`argv[0]` in `main()`) to know whether the code is under test. ## How do I temporarily disable a test? If you have a broken test that you cannot fix right away, you can add the `DISABLED_` prefix to its name. This will exclude it from execution. This is better than commenting out the code or using `#if 0`, as disabled tests are still compiled (and thus won't rot). To include disabled tests in test execution, just invoke the test program with the `--gtest_also_run_disabled_tests` flag. ## Is it OK if I have two separate `TEST(Foo, Bar)` test methods defined in different namespaces? Yes. The rule is **all test methods in the same test suite must use the same fixture class**. This means that the following is **allowed** because both tests use the same fixture class (`::testing::Test`). ```c++ namespace foo { TEST(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo namespace bar { TEST(CoolTest, DoSomething) { SUCCEED(); } } // namespace bar ``` However, the following code is **not allowed** and will produce a runtime error from GoogleTest because the test methods are using different test fixture classes with the same test suite name. ```c++ namespace foo { class CoolTest : public ::testing::Test {}; // Fixture foo::CoolTest TEST_F(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo namespace bar { class CoolTest : public ::testing::Test {}; // Fixture: bar::CoolTest TEST_F(CoolTest, DoSomething) { SUCCEED(); } } // namespace bar ``` gperftools-gperftools-2.18/vendor/googletest/docs/gmock_cheat_sheet.md000066400000000000000000000163261513545575200264150ustar00rootroot00000000000000# gMock Cheat Sheet ## Defining a Mock Class ### Mocking a Normal Class {#MockClass} Given ```cpp class Foo { public: virtual ~Foo(); virtual int GetSize() const = 0; virtual string Describe(const char* name) = 0; virtual string Describe(int type) = 0; virtual bool Process(Bar elem, int count) = 0; }; ``` (note that `~Foo()` **must** be virtual) we can define its mock as ```cpp #include class MockFoo : public Foo { public: MOCK_METHOD(int, GetSize, (), (const, override)); MOCK_METHOD(string, Describe, (const char* name), (override)); MOCK_METHOD(string, Describe, (int type), (override)); MOCK_METHOD(bool, Process, (Bar elem, int count), (override)); }; ``` To create a "nice" mock, which ignores all uninteresting calls, a "naggy" mock, which warns on all uninteresting calls, or a "strict" mock, which treats them as failures: ```cpp using ::testing::NiceMock; using ::testing::NaggyMock; using ::testing::StrictMock; NiceMock nice_foo; // The type is a subclass of MockFoo. NaggyMock naggy_foo; // The type is a subclass of MockFoo. StrictMock strict_foo; // The type is a subclass of MockFoo. ``` {: .callout .note} **Note:** A mock object is currently naggy by default. We may make it nice by default in the future. ### Mocking a Class Template {#MockTemplate} Class templates can be mocked just like any class. To mock ```cpp template class StackInterface { public: virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; ``` (note that all member functions that are mocked, including `~StackInterface()` **must** be virtual). ```cpp template class MockStack : public StackInterface { public: MOCK_METHOD(int, GetSize, (), (const, override)); MOCK_METHOD(void, Push, (const Elem& x), (override)); }; ``` ### Specifying Calling Conventions for Mock Functions If your mock function doesn't use the default calling convention, you can specify it by adding `Calltype(convention)` to `MOCK_METHOD`'s 4th parameter. For example, ```cpp MOCK_METHOD(bool, Foo, (int n), (Calltype(STDMETHODCALLTYPE))); MOCK_METHOD(int, Bar, (double x, double y), (const, Calltype(STDMETHODCALLTYPE))); ``` where `STDMETHODCALLTYPE` is defined by `` on Windows. ## Using Mocks in Tests {#UsingMocks} The typical work flow is: 1. Import the gMock names you need to use. All gMock symbols are in the `testing` namespace unless they are macros or otherwise noted. 2. Create the mock objects. 3. Optionally, set the default actions of the mock objects. 4. Set your expectations on the mock objects (How will they be called? What will they do?). 5. Exercise code that uses the mock objects; if necessary, check the result using googletest assertions. 6. When a mock object is destructed, gMock automatically verifies that all expectations on it have been satisfied. Here's an example: ```cpp using ::testing::Return; // #1 TEST(BarTest, DoesThis) { MockFoo foo; // #2 ON_CALL(foo, GetSize()) // #3 .WillByDefault(Return(1)); // ... other default actions ... EXPECT_CALL(foo, Describe(5)) // #4 .Times(3) .WillRepeatedly(Return("Category 5")); // ... other expectations ... EXPECT_EQ(MyProductionFunction(&foo), "good"); // #5 } // #6 ``` ## Setting Default Actions {#OnCall} gMock has a **built-in default action** for any function that returns `void`, `bool`, a numeric value, or a pointer. In C++11, it will additionally returns the default-constructed value, if one exists for the given type. To customize the default action for functions with return type `T`, use [`DefaultValue`](reference/mocking.md#DefaultValue). For example: ```cpp // Sets the default action for return type std::unique_ptr to // creating a new Buzz every time. DefaultValue>::SetFactory( [] { return std::make_unique(AccessLevel::kInternal); }); // When this fires, the default action of MakeBuzz() will run, which // will return a new Buzz object. EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")).Times(AnyNumber()); auto buzz1 = mock_buzzer_.MakeBuzz("hello"); auto buzz2 = mock_buzzer_.MakeBuzz("hello"); EXPECT_NE(buzz1, nullptr); EXPECT_NE(buzz2, nullptr); EXPECT_NE(buzz1, buzz2); // Resets the default action for return type std::unique_ptr, // to avoid interfere with other tests. DefaultValue>::Clear(); ``` To customize the default action for a particular method of a specific mock object, use [`ON_CALL`](reference/mocking.md#ON_CALL). `ON_CALL` has a similar syntax to `EXPECT_CALL`, but it is used for setting default behaviors when you do not require that the mock method is called. See [Knowing When to Expect](gmock_cook_book.md#UseOnCall) for a more detailed discussion. ## Setting Expectations {#ExpectCall} See [`EXPECT_CALL`](reference/mocking.md#EXPECT_CALL) in the Mocking Reference. ## Matchers {#MatcherList} See the [Matchers Reference](reference/matchers.md). ## Actions {#ActionList} See the [Actions Reference](reference/actions.md). ## Cardinalities {#CardinalityList} See the [`Times` clause](reference/mocking.md#EXPECT_CALL.Times) of `EXPECT_CALL` in the Mocking Reference. ## Expectation Order By default, expectations can be matched in *any* order. If some or all expectations must be matched in a given order, you can use the [`After` clause](reference/mocking.md#EXPECT_CALL.After) or [`InSequence` clause](reference/mocking.md#EXPECT_CALL.InSequence) of `EXPECT_CALL`, or use an [`InSequence` object](reference/mocking.md#InSequence). ## Verifying and Resetting a Mock gMock will verify the expectations on a mock object when it is destructed, or you can do it earlier: ```cpp using ::testing::Mock; ... // Verifies and removes the expectations on mock_obj; // returns true if and only if successful. Mock::VerifyAndClearExpectations(&mock_obj); ... // Verifies and removes the expectations on mock_obj; // also removes the default actions set by ON_CALL(); // returns true if and only if successful. Mock::VerifyAndClear(&mock_obj); ``` Do not set new expectations after verifying and clearing a mock after its use. Setting expectations after code that exercises the mock has undefined behavior. See [Using Mocks in Tests](gmock_for_dummies.md#using-mocks-in-tests) for more information. You can also tell gMock that a mock object can be leaked and doesn't need to be verified: ```cpp Mock::AllowLeak(&mock_obj); ``` ## Mock Classes gMock defines a convenient mock class template ```cpp class MockFunction { public: MOCK_METHOD(R, Call, (A1, ..., An)); }; ``` See this [recipe](gmock_cook_book.md#UsingCheckPoints) for one application of it. ## Flags | Flag | Description | | :----------------------------- | :---------------------------------------- | | `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | | `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | gperftools-gperftools-2.18/vendor/googletest/docs/gmock_cook_book.md000066400000000000000000004456121513545575200261120ustar00rootroot00000000000000# gMock Cookbook You can find recipes for using gMock here. If you haven't yet, please read [the dummy guide](gmock_for_dummies.md) first to make sure you understand the basics. {: .callout .note} **Note:** gMock lives in the `testing` name space. For readability, it is recommended to write `using ::testing::Foo;` once in your file before using the name `Foo` defined by gMock. We omit such `using` statements in this section for brevity, but you should do it in your own code. ## Creating Mock Classes Mock classes are defined as normal classes, using the `MOCK_METHOD` macro to generate mocked methods. The macro gets 3 or 4 parameters: ```cpp class MyMock { public: MOCK_METHOD(ReturnType, MethodName, (Args...)); MOCK_METHOD(ReturnType, MethodName, (Args...), (Specs...)); }; ``` The first 3 parameters are simply the method declaration, split into 3 parts. The 4th parameter accepts a closed list of qualifiers, which affect the generated method: * **`const`** - Makes the mocked method a `const` method. Required if overriding a `const` method. * **`override`** - Marks the method with `override`. Recommended if overriding a `virtual` method. * **`noexcept`** - Marks the method with `noexcept`. Required if overriding a `noexcept` method. * **`Calltype(...)`** - Sets the call type for the method (e.g. to `STDMETHODCALLTYPE`), useful in Windows. * **`ref(...)`** - Marks the method with the reference qualification specified. Required if overriding a method that has reference qualifications. Eg `ref(&)` or `ref(&&)`. ### Dealing with unprotected commas Unprotected commas, i.e. commas which are not surrounded by parentheses, prevent `MOCK_METHOD` from parsing its arguments correctly: {: .bad} ```cpp class MockFoo { public: MOCK_METHOD(std::pair, GetPair, ()); // Won't compile! MOCK_METHOD(bool, CheckMap, (std::map, bool)); // Won't compile! }; ``` Solution 1 - wrap with parentheses: {: .good} ```cpp class MockFoo { public: MOCK_METHOD((std::pair), GetPair, ()); MOCK_METHOD(bool, CheckMap, ((std::map), bool)); }; ``` Note that wrapping a return or argument type with parentheses is, in general, invalid C++. `MOCK_METHOD` removes the parentheses. Solution 2 - define an alias: {: .good} ```cpp class MockFoo { public: using BoolAndInt = std::pair; MOCK_METHOD(BoolAndInt, GetPair, ()); using MapIntDouble = std::map; MOCK_METHOD(bool, CheckMap, (MapIntDouble, bool)); }; ``` ### Mocking Private or Protected Methods You must always put a mock method definition (`MOCK_METHOD`) in a `public:` section of the mock class, regardless of the method being mocked being `public`, `protected`, or `private` in the base class. This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function from outside of the mock class. (Yes, C++ allows a subclass to change the access level of a virtual function in the base class.) Example: ```cpp class Foo { public: ... virtual bool Transform(Gadget* g) = 0; protected: virtual void Resume(); private: virtual int GetTimeOut(); }; class MockFoo : public Foo { public: ... MOCK_METHOD(bool, Transform, (Gadget* g), (override)); // The following must be in the public section, even though the // methods are protected or private in the base class. MOCK_METHOD(void, Resume, (), (override)); MOCK_METHOD(int, GetTimeOut, (), (override)); }; ``` ### Mocking Overloaded Methods You can mock overloaded functions as usual. No special attention is required: ```cpp class Foo { ... // Must be virtual as we'll inherit from Foo. virtual ~Foo(); // Overloaded on the types and/or numbers of arguments. virtual int Add(Element x); virtual int Add(int times, Element x); // Overloaded on the const-ness of this object. virtual Bar& GetBar(); virtual const Bar& GetBar() const; }; class MockFoo : public Foo { ... MOCK_METHOD(int, Add, (Element x), (override)); MOCK_METHOD(int, Add, (int times, Element x), (override)); MOCK_METHOD(Bar&, GetBar, (), (override)); MOCK_METHOD(const Bar&, GetBar, (), (const, override)); }; ``` {: .callout .note} **Note:** if you don't mock all versions of the overloaded method, the compiler will give you a warning about some methods in the base class being hidden. To fix that, use `using` to bring them in scope: ```cpp class MockFoo : public Foo { ... using Foo::Add; MOCK_METHOD(int, Add, (Element x), (override)); // We don't want to mock int Add(int times, Element x); ... }; ``` ### Mocking Class Templates You can mock class templates just like any class. ```cpp template class StackInterface { ... // Must be virtual as we'll inherit from StackInterface. virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; template class MockStack : public StackInterface { ... MOCK_METHOD(int, GetSize, (), (const, override)); MOCK_METHOD(void, Push, (const Elem& x), (override)); }; ``` ### Mocking Non-virtual Methods {#MockingNonVirtualMethods} gMock can mock non-virtual functions to be used in Hi-perf dependency injection. In this case, instead of sharing a common base class with the real class, your mock class will be *unrelated* to the real class, but contain methods with the same signatures. The syntax for mocking non-virtual methods is the *same* as mocking virtual methods (just don't add `override`): ```cpp // A simple packet stream class. None of its members is virtual. class ConcretePacketStream { public: void AppendPacket(Packet* new_packet); const Packet* GetPacket(size_t packet_number) const; size_t NumberOfPackets() const; ... }; // A mock packet stream class. It inherits from no other, but defines // GetPacket() and NumberOfPackets(). class MockPacketStream { public: MOCK_METHOD(const Packet*, GetPacket, (size_t packet_number), (const)); MOCK_METHOD(size_t, NumberOfPackets, (), (const)); ... }; ``` Note that the mock class doesn't define `AppendPacket()`, unlike the real class. That's fine as long as the test doesn't need to call it. Next, you need a way to say that you want to use `ConcretePacketStream` in production code, and use `MockPacketStream` in tests. Since the functions are not virtual and the two classes are unrelated, you must specify your choice at *compile time* (as opposed to run time). One way to do it is to templatize your code that needs to use a packet stream. More specifically, you will give your code a template type argument for the type of the packet stream. In production, you will instantiate your template with `ConcretePacketStream` as the type argument. In tests, you will instantiate the same template with `MockPacketStream`. For example, you may write: ```cpp template void CreateConnection(PacketStream* stream) { ... } template class PacketReader { public: void ReadPackets(PacketStream* stream, size_t packet_num); }; ``` Then you can use `CreateConnection()` and `PacketReader` in production code, and use `CreateConnection()` and `PacketReader` in tests. ```cpp MockPacketStream mock_stream; EXPECT_CALL(mock_stream, ...)...; .. set more expectations on mock_stream ... PacketReader reader(&mock_stream); ... exercise reader ... ``` ### Mocking Free Functions It is not possible to directly mock a free function (i.e. a C-style function or a static method). If you need to, you can rewrite your code to use an interface (abstract class). Instead of calling a free function (say, `OpenFile`) directly, introduce an interface for it and have a concrete subclass that calls the free function: ```cpp class FileInterface { public: ... virtual bool Open(const char* path, const char* mode) = 0; }; class File : public FileInterface { public: ... bool Open(const char* path, const char* mode) override { return OpenFile(path, mode); } }; ``` Your code should talk to `FileInterface` to open a file. Now it's easy to mock out the function. This may seem like a lot of hassle, but in practice you often have multiple related functions that you can put in the same interface, so the per-function syntactic overhead will be much lower. If you are concerned about the performance overhead incurred by virtual functions, and profiling confirms your concern, you can combine this with the recipe for [mocking non-virtual methods](#MockingNonVirtualMethods). Alternatively, instead of introducing a new interface, you can rewrite your code to accept a std::function instead of the free function, and then use [MockFunction](#MockFunction) to mock the std::function. ### Old-Style `MOCK_METHODn` Macros Before the generic `MOCK_METHOD` macro [was introduced in 2018](https://github.com/google/googletest/commit/c5f08bf91944ce1b19bcf414fa1760e69d20afc2), mocks where created using a family of macros collectively called `MOCK_METHODn`. These macros are still supported, though migration to the new `MOCK_METHOD` is recommended. The macros in the `MOCK_METHODn` family differ from `MOCK_METHOD`: * The general structure is `MOCK_METHODn(MethodName, ReturnType(Args))`, instead of `MOCK_METHOD(ReturnType, MethodName, (Args))`. * The number `n` must equal the number of arguments. * When mocking a const method, one must use `MOCK_CONST_METHODn`. * When mocking a class template, the macro name must be suffixed with `_T`. * In order to specify the call type, the macro name must be suffixed with `_WITH_CALLTYPE`, and the call type is the first macro argument. Old macros and their new equivalents:
Simple
Old MOCK_METHOD1(Foo, bool(int))
New MOCK_METHOD(bool, Foo, (int))
Const Method
Old MOCK_CONST_METHOD1(Foo, bool(int))
New MOCK_METHOD(bool, Foo, (int), (const))
Method in a Class Template
Old MOCK_METHOD1_T(Foo, bool(int))
New MOCK_METHOD(bool, Foo, (int))
Const Method in a Class Template
Old MOCK_CONST_METHOD1_T(Foo, bool(int))
New MOCK_METHOD(bool, Foo, (int), (const))
Method with Call Type
Old MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int))
New MOCK_METHOD(bool, Foo, (int), (Calltype(STDMETHODCALLTYPE)))
Const Method with Call Type
Old MOCK_CONST_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int))
New MOCK_METHOD(bool, Foo, (int), (const, Calltype(STDMETHODCALLTYPE)))
Method with Call Type in a Class Template
Old MOCK_METHOD1_T_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int))
New MOCK_METHOD(bool, Foo, (int), (Calltype(STDMETHODCALLTYPE)))
Const Method with Call Type in a Class Template
Old MOCK_CONST_METHOD1_T_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int))
New MOCK_METHOD(bool, Foo, (int), (const, Calltype(STDMETHODCALLTYPE)))
### The Nice, the Strict, and the Naggy {#NiceStrictNaggy} If a mock method has no `EXPECT_CALL` spec but is called, we say that it's an "uninteresting call", and the default action (which can be specified using `ON_CALL()`) of the method will be taken. Currently, an uninteresting call will also by default cause gMock to print a warning. However, sometimes you may want to ignore these uninteresting calls, and sometimes you may want to treat them as errors. gMock lets you make the decision on a per-mock-object basis. Suppose your test uses a mock class `MockFoo`: ```cpp TEST(...) { MockFoo mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` If a method of `mock_foo` other than `DoThis()` is called, you will get a warning. However, if you rewrite your test to use `NiceMock` instead, you can suppress the warning: ```cpp using ::testing::NiceMock; TEST(...) { NiceMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` `NiceMock` is a subclass of `MockFoo`, so it can be used wherever `MockFoo` is accepted. It also works if `MockFoo`'s constructor takes some arguments, as `NiceMock` "inherits" `MockFoo`'s constructors: ```cpp using ::testing::NiceMock; TEST(...) { NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` The usage of `StrictMock` is similar, except that it makes all uninteresting calls failures: ```cpp using ::testing::StrictMock; TEST(...) { StrictMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... // The test will fail if a method of mock_foo other than DoThis() // is called. } ``` {: .callout .note} NOTE: `NiceMock` and `StrictMock` only affects *uninteresting* calls (calls of *methods* with no expectations); they do not affect *unexpected* calls (calls of methods with expectations, but they don't match). See [Understanding Uninteresting vs Unexpected Calls](#uninteresting-vs-unexpected). There are some caveats though (sadly they are side effects of C++'s limitations): 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD` macro **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. 2. `NiceMock` and `StrictMock` may not work correctly if the destructor of `MockFoo` is not virtual. We would like to fix this, but it requires cleaning up existing tests. Finally, you should be **very cautious** about when to use naggy or strict mocks, as they tend to make tests more brittle and harder to maintain. When you refactor your code without changing its externally visible behavior, ideally you shouldn't need to update any tests. If your code interacts with a naggy mock, however, you may start to get spammed with warnings as the result of your change. Worse, if your code interacts with a strict mock, your tests may start to fail and you'll be forced to fix them. Our general recommendation is to use nice mocks (not yet the default) most of the time, use naggy mocks (the current default) when developing or debugging tests, and use strict mocks only as the last resort. ### Simplifying the Interface without Breaking Existing Code {#SimplerInterfaces} Sometimes a method has a long list of arguments that is mostly uninteresting. For example: ```cpp class LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const struct tm* tm_time, const char* message, size_t message_len) = 0; }; ``` This method's argument list is lengthy and hard to work with (the `message` argument is not even 0-terminated). If we mock it as is, using the mock will be awkward. If, however, we try to simplify this interface, we'll need to fix all clients depending on it, which is often infeasible. The trick is to redispatch the method in the mock class: ```cpp class ScopedMockLog : public LogSink { public: ... void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const tm* tm_time, const char* message, size_t message_len) override { // We are only interested in the log severity, full file name, and // log message. Log(severity, full_filename, std::string(message, message_len)); } // Implements the mock method: // // void Log(LogSeverity severity, // const string& file_path, // const string& message); MOCK_METHOD(void, Log, (LogSeverity severity, const string& file_path, const string& message)); }; ``` By defining a new mock method with a trimmed argument list, we make the mock class more user-friendly. This technique may also be applied to make overloaded methods more amenable to mocking. For example, when overloads have been used to implement default arguments: ```cpp class MockTurtleFactory : public TurtleFactory { public: Turtle* MakeTurtle(int length, int weight) override { ... } Turtle* MakeTurtle(int length, int weight, int speed) override { ... } // the above methods delegate to this one: MOCK_METHOD(Turtle*, DoMakeTurtle, ()); }; ``` This allows tests that don't care which overload was invoked to avoid specifying argument matchers: ```cpp ON_CALL(factory, DoMakeTurtle) .WillByDefault(Return(MakeMockTurtle())); ``` ### Alternative to Mocking Concrete Classes Often you may find yourself using classes that don't implement interfaces. In order to test your code that uses such a class (let's call it `Concrete`), you may be tempted to make the methods of `Concrete` virtual and then mock it. Try not to do that. Making a non-virtual function virtual is a big decision. It creates an extension point where subclasses can tweak your class' behavior. This weakens your control on the class because now it's harder to maintain the class invariants. You should make a function virtual only when there is a valid reason for a subclass to override it. Mocking concrete classes directly is problematic as it creates a tight coupling between the class and the tests - any small change in the class may invalidate your tests and make test maintenance a pain. To avoid such problems, many programmers have been practicing "coding to interfaces": instead of talking to the `Concrete` class, your code would define an interface and talk to it. Then you implement that interface as an adaptor on top of `Concrete`. In tests, you can easily mock that interface to observe how your code is doing. This technique incurs some overhead: * You pay the cost of virtual function calls (usually not a problem). * There is more abstraction for the programmers to learn. However, it can also bring significant benefits in addition to better testability: * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. Some people worry that if everyone is practicing this technique, they will end up writing lots of redundant code. This concern is totally understandable. However, there are two reasons why it may not be the case: * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. You need to weigh the pros and cons carefully for your particular problem, but I'd like to assure you that the Java community has been practicing this for a long time and it's a proven effective technique applicable in a wide variety of situations. :-) ### Delegating Calls to a Fake {#DelegatingToFake} Some times you have a non-trivial fake implementation of an interface. For example: ```cpp class Foo { public: virtual ~Foo() {} virtual char DoThis(int n) = 0; virtual void DoThat(const char* s, int* p) = 0; }; class FakeFoo : public Foo { public: char DoThis(int n) override { return (n > 0) ? '+' : (n < 0) ? '-' : '0'; } void DoThat(const char* s, int* p) override { *p = strlen(s); } }; ``` Now you want to mock this interface such that you can set expectations on it. However, you also want to use `FakeFoo` for the default behavior, as duplicating it in the mock object is, well, a lot of work. When you define the mock class using gMock, you can have it delegate its default action to a fake class you already have, using this pattern: ```cpp class MockFoo : public Foo { public: // Normal mock method definitions using gMock. MOCK_METHOD(char, DoThis, (int n), (override)); MOCK_METHOD(void, DoThat, (const char* s, int* p), (override)); // Delegates the default actions of the methods to a FakeFoo object. // This must be called *before* the custom ON_CALL() statements. void DelegateToFake() { ON_CALL(*this, DoThis).WillByDefault([this](int n) { return fake_.DoThis(n); }); ON_CALL(*this, DoThat).WillByDefault([this](const char* s, int* p) { fake_.DoThat(s, p); }); } private: FakeFoo fake_; // Keeps an instance of the fake in the mock. }; ``` With that, you can use `MockFoo` in your tests as usual. Just remember that if you don't explicitly set an action in an `ON_CALL()` or `EXPECT_CALL()`, the fake will be called upon to do it.: ```cpp using ::testing::_; TEST(AbcTest, Xyz) { MockFoo foo; foo.DelegateToFake(); // Enables the fake for delegation. // Put your ON_CALL(foo, ...)s here, if any. // No action specified, meaning to use the default action. EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(foo, DoThat(_, _)); int n = 0; EXPECT_EQ(foo.DoThis(5), '+'); // FakeFoo::DoThis() is invoked. foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. EXPECT_EQ(n, 2); } ``` **Some tips:** * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), use [this technique](#SelectOverload); to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. For instance, if class `Foo` has methods `char DoThis(int n)` and `bool DoThis(double x) const`, and you want to invoke the latter, you need to write `Invoke(&fake_, static_cast(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` (The strange-looking thing inside the angled brackets of `static_cast` is the type of a function pointer to the second `DoThis()` method.). * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. Regarding the tip on mixing a mock and a fake, here's an example on why it may be a bad sign: Suppose you have a class `System` for low-level system operations. In particular, it does file and I/O operations. And suppose you want to test how your code uses `System` to do I/O, and you just want the file operations to work normally. If you mock out the entire `System` class, you'll have to provide a fake implementation for the file operation part, which suggests that `System` is taking on too many roles. Instead, you can define a `FileOps` interface and an `IOOps` interface and split `System`'s functionalities into the two. Then you can mock `IOOps` without mocking `FileOps`. ### Delegating Calls to a Real Object When using testing doubles (mocks, fakes, stubs, and etc), sometimes their behaviors will differ from those of the real objects. This difference could be either intentional (as in simulating an error such that you can test the error handling code) or unintentional. If your mocks have different behaviors than the real objects by mistake, you could end up with code that passes the tests but fails in production. You can use the *delegating-to-real* technique to ensure that your mock has the same behavior as the real object while retaining the ability to validate calls. This technique is very similar to the [delegating-to-fake](#DelegatingToFake) technique, the difference being that we use a real object instead of a fake. Here's an example: ```cpp using ::testing::AtLeast; class MockFoo : public Foo { public: MockFoo() { // By default, all calls are delegated to the real object. ON_CALL(*this, DoThis).WillByDefault([this](int n) { return real_.DoThis(n); }); ON_CALL(*this, DoThat).WillByDefault([this](const char* s, int* p) { real_.DoThat(s, p); }); ... } MOCK_METHOD(char, DoThis, ...); MOCK_METHOD(void, DoThat, ...); ... private: Foo real_; }; ... MockFoo mock; EXPECT_CALL(mock, DoThis()) .Times(3); EXPECT_CALL(mock, DoThat("Hi")) .Times(AtLeast(1)); ... use mock in test ... ``` With this, gMock will verify that your code made the right calls (with the right arguments, in the right order, called the right number of times, etc), and a real object will answer the calls (so the behavior will be the same as in production). This gives you the best of both worlds. ### Delegating Calls to a Parent Class Ideally, you should code to interfaces, whose methods are all pure virtual. In reality, sometimes you do need to mock a virtual method that is not pure (i.e, it already has an implementation). For example: ```cpp class Foo { public: virtual ~Foo(); virtual void Pure(int n) = 0; virtual int Concrete(const char* str) { ... } }; class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD(void, Pure, (int n), (override)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD(int, Concrete, (const char* str), (override)); }; ``` Sometimes you may want to call `Foo::Concrete()` instead of `MockFoo::Concrete()`. Perhaps you want to do it as part of a stub action, or perhaps your test doesn't need to mock `Concrete()` at all (but it would be oh-so painful to have to define a new mock class whenever you don't need to mock one of its methods). You can call `Foo::Concrete()` inside an action by: ```cpp ... EXPECT_CALL(foo, Concrete).WillOnce([&foo](const char* str) { return foo.Foo::Concrete(str); }); ``` or tell the mock object that you don't want to mock `Concrete()`: ```cpp ... ON_CALL(foo, Concrete).WillByDefault([&foo](const char* str) { return foo.Foo::Concrete(str); }); ``` (Why don't we just write `{ return foo.Concrete(str); }`? If you do that, `MockFoo::Concrete()` will be called (and cause an infinite recursion) since `Foo::Concrete()` is virtual. That's just how C++ works.) ## Using Matchers ### Matching Argument Values Exactly You can specify exactly which arguments a mock method is expecting: ```cpp using ::testing::Return; ... EXPECT_CALL(foo, DoThis(5)) .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", bar)); ``` ### Using Simple Matchers You can use matchers to match arguments that have a certain property: ```cpp using ::testing::NotNull; using ::testing::Return; ... EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", NotNull())); // The second argument must not be NULL. ``` A frequently used matcher is `_`, which matches anything: ```cpp EXPECT_CALL(foo, DoThat(_, NotNull())); ``` ### Combining Matchers {#CombiningMatchers} You can build complex matchers from existing ones using `AllOf()`, `AllOfArray()`, `AnyOf()`, `AnyOfArray()` and `Not()`: ```cpp using ::testing::AllOf; using ::testing::Gt; using ::testing::HasSubstr; using ::testing::Ne; using ::testing::Not; ... // The argument must be > 5 and != 10. EXPECT_CALL(foo, DoThis(AllOf(Gt(5), Ne(10)))); // The first argument must not contain sub-string "blah". EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), NULL)); ``` Matchers are function objects, and parametrized matchers can be composed just like any other function. However because their types can be long and rarely provide meaningful information, it can be easier to express them with C++14 generic lambdas to avoid specifying types. For example, ```cpp using ::testing::Contains; using ::testing::Property; inline constexpr auto HasFoo = [](const auto& f) { return Property("foo", &MyClass::foo, Contains(f)); }; ... EXPECT_THAT(x, HasFoo("blah")); ``` ### Casting Matchers {#SafeMatcherCast} gMock matchers are statically typed, meaning that the compiler can catch your mistake if you use a matcher of the wrong type (for example, if you use `Eq(5)` to match a `string` argument). Good for you! Sometimes, however, you know what you're doing and want the compiler to give you some slack. One example is that you have a matcher for `long` and the argument you want to match is `int`. While the two types aren't exactly the same, there is nothing really wrong with using a `Matcher` to match an `int` - after all, we can first convert the `int` argument to a `long` losslessly before giving it to the matcher. To support this need, gMock gives you the `SafeMatcherCast(m)` function. It casts a matcher `m` to type `Matcher`. To ensure safety, gMock checks that (let `U` be the type `m` accepts : 1. Type `T` can be *implicitly* cast to type `U`; 2. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and 3. When `U` is a non-const reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). The code won't compile if any of these conditions isn't met. Here's one example: ```cpp using ::testing::SafeMatcherCast; // A base class and a child class. class Base { ... }; class Derived : public Base { ... }; class MockFoo : public Foo { public: MOCK_METHOD(void, DoThis, (Derived* derived), (override)); }; ... MockFoo foo; // m is a Matcher we got from somewhere. EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); ``` If you find `SafeMatcherCast(m)` too limiting, you can use a similar function `MatcherCast(m)`. The difference is that `MatcherCast` works as long as you can `static_cast` type `T` to type `U`. `MatcherCast` essentially lets you bypass C++'s type system (`static_cast` isn't always safe as it could throw away information, for example), so be careful not to misuse/abuse it. ### Selecting Between Overloaded Functions {#SelectOverload} If you expect an overloaded function to be called, the compiler may need some help on which overloaded version it is. To disambiguate functions overloaded on the const-ness of this object, use the `Const()` argument wrapper. ```cpp using ::testing::ReturnRef; class MockFoo : public Foo { ... MOCK_METHOD(Bar&, GetBar, (), (override)); MOCK_METHOD(const Bar&, GetBar, (), (const, override)); }; ... MockFoo foo; Bar bar1, bar2; EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). .WillOnce(ReturnRef(bar1)); EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). .WillOnce(ReturnRef(bar2)); ``` (`Const()` is defined by gMock and returns a `const` reference to its argument.) To disambiguate overloaded functions with the same number of arguments but different argument types, you may need to specify the exact type of a matcher, either by wrapping your matcher in `Matcher()`, or using a matcher whose type is fixed (`TypedEq`, `An()`, etc): ```cpp using ::testing::An; using ::testing::Matcher; using ::testing::TypedEq; class MockPrinter : public Printer { public: MOCK_METHOD(void, Print, (int n), (override)); MOCK_METHOD(void, Print, (char c), (override)); }; TEST(PrinterTest, Print) { MockPrinter printer; EXPECT_CALL(printer, Print(An())); // void Print(int); EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); printer.Print(3); printer.Print(6); printer.Print('a'); } ``` ### Performing Different Actions Based on the Arguments When a mock method is called, the *last* matching expectation that's still active will be selected (think "newer overrides older"). So, you can make a method do different things depending on its argument values like this: ```cpp using ::testing::_; using ::testing::Lt; using ::testing::Return; ... // The default case. EXPECT_CALL(foo, DoThis(_)) .WillRepeatedly(Return('b')); // The more specific case. EXPECT_CALL(foo, DoThis(Lt(5))) .WillRepeatedly(Return('a')); ``` Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will be returned; otherwise `'b'` will be returned. ### Matching Multiple Arguments as a Whole Sometimes it's not enough to match the arguments individually. For example, we may want to say that the first argument must be less than the second argument. The `With()` clause allows us to match all arguments of a mock function as a whole. For example, ```cpp using ::testing::_; using ::testing::Ne; using ::testing::Lt; ... EXPECT_CALL(foo, InRange(Ne(0), _)) .With(Lt()); ``` says that the first argument of `InRange()` must not be 0, and must be less than the second argument. The expression inside `With()` must be a matcher of type `Matcher>`, where `A1`, ..., `An` are the types of the function arguments. You can also write `AllArgs(m)` instead of `m` inside `.With()`. The two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable than `.With(Lt())`. You can use `Args(m)` to match the `n` selected arguments (as a tuple) against `m`. For example, ```cpp using ::testing::_; using ::testing::AllOf; using ::testing::Args; using ::testing::Lt; ... EXPECT_CALL(foo, Blah) .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); ``` says that `Blah` will be called with arguments `x`, `y`, and `z` where `x < y < z`. Note that in this example, it wasn't necessary to specify the positional matchers. As a convenience and example, gMock provides some matchers for 2-tuples, including the `Lt()` matcher above. See [Multi-argument Matchers](reference/matchers.md#MultiArgMatchers) for the complete list. Note that if you want to pass the arguments to a predicate of your own (e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be written to take a `std::tuple` as its argument; gMock will pass the `n` selected arguments as *one* single tuple to the predicate. ### Using Matchers as Predicates Have you noticed that a matcher is just a fancy predicate that also knows how to describe itself? Many existing algorithms take predicates as arguments (e.g. those defined in STL's `` header), and it would be a shame if gMock matchers were not allowed to participate. Luckily, you can use a matcher where a unary predicate functor is expected by wrapping it inside the `Matches()` function. For example, ```cpp #include #include using ::testing::Matches; using ::testing::Ge; vector v; ... // How many elements in v are >= 10? const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); ``` Since you can build complex matchers from simpler ones easily using gMock, this gives you a way to conveniently construct composite predicates (doing the same using STL's `` header is just painful). For example, here's a predicate that's satisfied by any number that is >= 0, <= 100, and != 50: ```cpp using ::testing::AllOf; using ::testing::Ge; using ::testing::Le; using ::testing::Matches; using ::testing::Ne; ... Matches(AllOf(Ge(0), Le(100), Ne(50))) ``` ### Using Matchers in googletest Assertions See [`EXPECT_THAT`](reference/assertions.md#EXPECT_THAT) in the Assertions Reference. ### Using Predicates as Matchers gMock provides a set of built-in matchers for matching arguments with expected values—see the [Matchers Reference](reference/matchers.md) for more information. In case you find the built-in set lacking, you can use an arbitrary unary predicate function or functor as a matcher - as long as the predicate accepts a value of the type you want. You do this by wrapping the predicate inside the `Truly()` function, for example: ```cpp using ::testing::Truly; int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } ... // Bar() must be called with an even number. EXPECT_CALL(foo, Bar(Truly(IsEven))); ``` Note that the predicate function / functor doesn't have to return `bool`. It works as long as the return value can be used as the condition in the statement `if (condition) ...`. ### Matching Arguments that Are Not Copyable When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, gMock saves away a copy of `bar`. When `Foo()` is called later, gMock compares the argument to `Foo()` with the saved copy of `bar`. This way, you don't need to worry about `bar` being modified or destroyed after the `EXPECT_CALL()` is executed. The same is true when you use matchers like `Eq(bar)`, `Le(bar)`, and so on. But what if `bar` cannot be copied (i.e. has no copy constructor)? You could define your own matcher function or callback and use it with `Truly()`, as the previous couple of recipes have shown. Or, you may be able to get away from it if you can guarantee that `bar` won't be changed after the `EXPECT_CALL()` is executed. Just tell gMock that it should save a reference to `bar`, instead of a copy of it. Here's how: ```cpp using ::testing::Eq; using ::testing::Lt; ... // Expects that Foo()'s argument == bar. EXPECT_CALL(mock_obj, Foo(Eq(std::ref(bar)))); // Expects that Foo()'s argument < bar. EXPECT_CALL(mock_obj, Foo(Lt(std::ref(bar)))); ``` Remember: if you do this, don't change `bar` after the `EXPECT_CALL()`, or the result is undefined. ### Validating a Member of an Object Often a mock function takes a reference to object as an argument. When matching the argument, you may not want to compare the entire object against a fixed object, as that may be over-specification. Instead, you may need to validate a certain member variable or the result of a certain getter method of the object. You can do this with `Field()` and `Property()`. More specifically, ```cpp Field(&Foo::bar, m) ``` is a matcher that matches a `Foo` object whose `bar` member variable satisfies matcher `m`. ```cpp Property(&Foo::baz, m) ``` is a matcher that matches a `Foo` object whose `baz()` method returns a value that satisfies matcher `m`. For example: | Expression | Description | | :--------------------------- | :--------------------------------------- | | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no argument and be declared as `const`. Don't use `Property()` against member functions that you do not own, because taking addresses of functions is fragile and generally not part of the contract of the function. `Field()` and `Property()` can also match plain pointers to objects. For instance, ```cpp using ::testing::Field; using ::testing::Ge; ... Field(&Foo::number, Ge(3)) ``` matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, the match will always fail regardless of the inner matcher. What if you want to validate more than one members at the same time? Remember that there are [`AllOf()` and `AllOfArray()`](#CombiningMatchers). Finally `Field()` and `Property()` provide overloads that take the field or property names as the first argument to include it in the error message. This can be useful when creating combined matchers. ```cpp using ::testing::AllOf; using ::testing::Field; using ::testing::Matcher; using ::testing::SafeMatcherCast; Matcher IsFoo(const Foo& foo) { return AllOf(Field("some_field", &Foo::some_field, foo.some_field), Field("other_field", &Foo::other_field, foo.other_field), Field("last_field", &Foo::last_field, foo.last_field)); } ``` ### Validating the Value Pointed to by a Pointer Argument C++ functions often take pointers as arguments. You can use matchers like `IsNull()`, `NotNull()`, and other comparison matchers to match a pointer, but what if you want to make sure the value *pointed to* by the pointer, instead of the pointer itself, has a certain property? Well, you can use the `Pointee(m)` matcher. `Pointee(m)` matches a pointer if and only if `m` matches the value the pointer points to. For example: ```cpp using ::testing::Ge; using ::testing::Pointee; ... EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); ``` expects `foo.Bar()` to be called with a pointer that points to a value greater than or equal to 3. One nice thing about `Pointee()` is that it treats a `NULL` pointer as a match failure, so you can write `Pointee(m)` instead of ```cpp using ::testing::AllOf; using ::testing::NotNull; using ::testing::Pointee; ... AllOf(NotNull(), Pointee(m)) ``` without worrying that a `NULL` pointer will crash your test. Also, did we tell you that `Pointee()` works with both raw pointers **and** smart pointers (`std::unique_ptr`, `std::shared_ptr`, etc)? What if you have a pointer to pointer? You guessed it - you can use nested `Pointee()` to probe deeper inside the value. For example, `Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer that points to a number less than 3 (what a mouthful...). ### Defining a Custom Matcher Class {#CustomMatcherClass} Most matchers can be simply defined using [the MATCHER* macros](#NewMatchers), which are terse and flexible, and produce good error messages. However, these macros are not very explicit about the interfaces they create and are not always suitable, especially for matchers that will be widely reused. For more advanced cases, you may need to define your own matcher class. A custom matcher allows you to test a specific invariant property of that object. Let's take a look at how to do so. Imagine you have a mock function that takes an object of type `Foo`, which has an `int bar()` method and an `int baz()` method. You want to constrain that the argument's `bar()` value plus its `baz()` value is a given number. (This is an invariant.) Here's how we can write and use a matcher class to do so: ```cpp class BarPlusBazEqMatcher { public: using is_gtest_matcher = void; explicit BarPlusBazEqMatcher(int expected_sum) : expected_sum_(expected_sum) {} bool MatchAndExplain(const Foo& foo, std::ostream* /* listener */) const { return (foo.bar() + foo.baz()) == expected_sum_; } void DescribeTo(std::ostream* os) const { *os << "bar() + baz() equals " << expected_sum_; } void DescribeNegationTo(std::ostream* os) const { *os << "bar() + baz() does not equal " << expected_sum_; } private: const int expected_sum_; }; ::testing::Matcher BarPlusBazEq(int expected_sum) { return BarPlusBazEqMatcher(expected_sum); } ... Foo foo; EXPECT_THAT(foo, BarPlusBazEq(5))...; ``` ### Matching Containers Sometimes an STL container (e.g. list, vector, map, ...) is passed to a mock function and you may want to validate it. Since most STL containers support the `==` operator, you can write `Eq(expected_container)` or simply `expected_container` to match a container exactly. Sometimes, though, you may want to be more flexible (for example, the first element must be an exact match, but the second element can be any positive number, and so on). Also, containers used in tests often have a small number of elements, and having to define the expected container out-of-line is a bit of a hassle. You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in such cases: ```cpp using ::testing::_; using ::testing::ElementsAre; using ::testing::Gt; ... MOCK_METHOD(void, Foo, (const vector& numbers), (override)); ... EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); ``` The above matcher says that the container must have 4 elements, which must be 1, greater than 0, anything, and 5 respectively. If you instead write: ```cpp using ::testing::_; using ::testing::Gt; using ::testing::UnorderedElementsAre; ... MOCK_METHOD(void, Foo, (const vector& numbers), (override)); ... EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); ``` It means that the container must have 4 elements, which (under some permutation) must be 1, greater than 0, anything, and 5 respectively. As an alternative you can place the arguments in a C-style array and use `ElementsAreArray()` or `UnorderedElementsAreArray()` instead: ```cpp using ::testing::ElementsAreArray; ... // ElementsAreArray accepts an array of element values. const int expected_vector1[] = {1, 5, 2, 4, ...}; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); // Or, an array of element matchers. Matcher expected_vector2[] = {1, Gt(2), _, 3, ...}; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); ``` In case the array needs to be dynamically created (and therefore the array size cannot be inferred by the compiler), you can give `ElementsAreArray()` an additional argument to specify the array size: ```cpp using ::testing::ElementsAreArray; ... int* const expected_vector3 = new int[count]; ... fill expected_vector3 with values ... EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); ``` Use `Pair` when comparing maps or other associative containers. {% raw %} ```cpp using ::testing::UnorderedElementsAre; using ::testing::Pair; ... absl::flat_hash_map m = {{"a", 1}, {"b", 2}, {"c", 3}}; EXPECT_THAT(m, UnorderedElementsAre( Pair("a", 1), Pair("b", 2), Pair("c", 3))); ``` {% endraw %} **Tips:** * `ElementsAre*()` can be used to match *any* container that implements the STL iterator pattern (i.e. it has a `const_iterator` type and supports `begin()/end()`), not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. * You can use nested `ElementsAre*()` to match nested (multi-dimensional) containers. * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. * The order of elements *matters* for `ElementsAre*()`. If you are using it with containers whose element order are undefined (such as a `std::unordered_map`) you should use `UnorderedElementsAre`. ### Sharing Matchers Under the hood, a gMock matcher object consists of a pointer to a ref-counted implementation object. Copying matchers is allowed and very efficient, as only the pointer is copied. When the last matcher that references the implementation object dies, the implementation object will be deleted. Therefore, if you have some complex matcher that you want to use again and again, there is no need to build it every time. Just assign it to a matcher variable and use that variable repeatedly! For example, ```cpp using ::testing::AllOf; using ::testing::Gt; using ::testing::Le; using ::testing::Matcher; ... Matcher in_range = AllOf(Gt(5), Le(10)); ... use in_range as a matcher in multiple EXPECT_CALLs ... ``` ### Matchers must have no side-effects {#PureMatchers} {: .callout .warning} WARNING: gMock does not guarantee when or how many times a matcher will be invoked. Therefore, all matchers must be *purely functional*: they cannot have any side effects, and the match result must not depend on anything other than the matcher's parameters and the value being matched. This requirement must be satisfied no matter how a matcher is defined (e.g., if it is one of the standard matchers, or a custom matcher). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and gMock. ## Setting Expectations ### Knowing When to Expect {#UseOnCall} **`ON_CALL`** is likely the *single most under-utilized construct* in gMock. There are basically two constructs for defining the behavior of a mock object: `ON_CALL` and `EXPECT_CALL`. The difference? `ON_CALL` defines what happens when a mock method is called, but doesn't imply any expectation on the method being called. `EXPECT_CALL` not only defines the behavior, but also sets an expectation that the method will be called with the given arguments, for the given number of times (and *in the given order* when you specify the order too). Since `EXPECT_CALL` does more, isn't it better than `ON_CALL`? Not really. Every `EXPECT_CALL` adds a constraint on the behavior of the code under test. Having more constraints than necessary is *baaad* - even worse than not having enough constraints. This may be counter-intuitive. How could tests that verify more be worse than tests that verify less? Isn't verification the whole point of tests? The answer lies in *what* a test should verify. **A good test verifies the contract of the code.** If a test over-specifies, it doesn't leave enough freedom to the implementation. As a result, changing the implementation without breaking the contract (e.g. refactoring and optimization), which should be perfectly fine to do, can break such tests. Then you have to spend time fixing them, only to see them broken again the next time the implementation is changed. Keep in mind that one doesn't have to verify more than one property in one test. In fact, **it's a good style to verify only one thing in one test.** If you do that, a bug will likely break only one or two tests instead of dozens (which case would you rather debug?). If you are also in the habit of giving tests descriptive names that tell what they verify, you can often easily guess what's wrong just from the test log itself. So use `ON_CALL` by default, and only use `EXPECT_CALL` when you actually intend to verify that the call is made. For example, you may have a bunch of `ON_CALL`s in your test fixture to set the common mock behavior shared by all tests in the same group, and write (scarcely) different `EXPECT_CALL`s in different `TEST_F`s to verify different aspects of the code's behavior. Compared with the style where each `TEST` has many `EXPECT_CALL`s, this leads to tests that are more resilient to implementational changes (and thus less likely to require maintenance) and makes the intent of the tests more obvious (so they are easier to maintain when you do need to maintain them). If you are bothered by the "Uninteresting mock function call" message printed when a mock method without an `EXPECT_CALL` is called, you may use a `NiceMock` instead to suppress all such messages for the mock object, or suppress the message for specific methods by adding `EXPECT_CALL(...).Times(AnyNumber())`. DO NOT suppress it by blindly adding an `EXPECT_CALL(...)`, or you'll have a test that's a pain to maintain. ### Ignoring Uninteresting Calls If you are not interested in how a mock method is called, just don't say anything about it. In this case, if the method is ever called, gMock will perform its default action to allow the test program to continue. If you are not happy with the default action taken by gMock, you can override it using `DefaultValue::Set()` (described [here](#DefaultValue)) or `ON_CALL()`. Please note that once you expressed interest in a particular mock method (via `EXPECT_CALL()`), all invocations to it must match some expectation. If this function is called but the arguments don't match any `EXPECT_CALL()` statement, it will be an error. ### Disallowing Unexpected Calls If a mock method shouldn't be called at all, explicitly say so: ```cpp using ::testing::_; ... EXPECT_CALL(foo, Bar(_)) .Times(0); ``` If some calls to the method are allowed, but the rest are not, just list all the expected calls: ```cpp using ::testing::AnyNumber; using ::testing::Gt; ... EXPECT_CALL(foo, Bar(5)); EXPECT_CALL(foo, Bar(Gt(10))) .Times(AnyNumber()); ``` A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` statements will be an error. ### Understanding Uninteresting vs Unexpected Calls {#uninteresting-vs-unexpected} *Uninteresting* calls and *unexpected* calls are different concepts in gMock. *Very* different. A call `x.Y(...)` is **uninteresting** if there's *not even a single* `EXPECT_CALL(x, Y(...))` set. In other words, the test isn't interested in the `x.Y()` method at all, as evident in that the test doesn't care to say anything about it. A call `x.Y(...)` is **unexpected** if there are *some* `EXPECT_CALL(x, Y(...))`s set, but none of them matches the call. Put another way, the test is interested in the `x.Y()` method (therefore it explicitly sets some `EXPECT_CALL` to verify how it's called); however, the verification fails as the test doesn't expect this particular call to happen. **An unexpected call is always an error,** as the code under test doesn't behave the way the test expects it to behave. **By default, an uninteresting call is not an error,** as it violates no constraint specified by the test. (gMock's philosophy is that saying nothing means there is no constraint.) However, it leads to a warning, as it *might* indicate a problem (e.g. the test author might have forgotten to specify a constraint). In gMock, `NiceMock` and `StrictMock` can be used to make a mock class "nice" or "strict". How does this affect uninteresting calls and unexpected calls? A **nice mock** suppresses uninteresting call *warnings*. It is less chatty than the default mock, but otherwise is the same. If a test fails with a default mock, it will also fail using a nice mock instead. And vice versa. Don't expect making a mock nice to change the test's result. A **strict mock** turns uninteresting call warnings into errors. So making a mock strict may change the test's result. Let's look at an example: ```cpp TEST(...) { NiceMock mock_registry; EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) .WillRepeatedly(Return("Larry Page")); // Use mock_registry in code under test. ... &mock_registry ... } ``` The sole `EXPECT_CALL` here says that all calls to `GetDomainOwner()` must have `"google.com"` as the argument. If `GetDomainOwner("yahoo.com")` is called, it will be an unexpected call, and thus an error. *Having a nice mock doesn't change the severity of an unexpected call.* So how do we tell gMock that `GetDomainOwner()` can be called with some other arguments as well? The standard technique is to add a "catch all" `EXPECT_CALL`: ```cpp EXPECT_CALL(mock_registry, GetDomainOwner(_)) .Times(AnyNumber()); // catches all other calls to this method. EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) .WillRepeatedly(Return("Larry Page")); ``` Remember that `_` is the wildcard matcher that matches anything. With this, if `GetDomainOwner("google.com")` is called, it will do what the second `EXPECT_CALL` says; if it is called with a different argument, it will do what the first `EXPECT_CALL` says. Note that the order of the two `EXPECT_CALL`s is important, as a newer `EXPECT_CALL` takes precedence over an older one. For more on uninteresting calls, nice mocks, and strict mocks, read ["The Nice, the Strict, and the Naggy"](#NiceStrictNaggy). ### Ignoring Uninteresting Arguments {#ParameterlessExpectations} If your test doesn't care about the parameters (it only cares about the number or order of calls), you can often simply omit the parameter list: ```cpp // Expect foo.Bar( ... ) twice with any arguments. EXPECT_CALL(foo, Bar).Times(2); // Delegate to the given method whenever the factory is invoked. ON_CALL(foo_factory, MakeFoo) .WillByDefault(&BuildFooForTest); ``` This functionality is only available when a method is not overloaded; to prevent unexpected behavior it is a compilation error to try to set an expectation on a method where the specific overload is ambiguous. You can work around this by supplying a [simpler mock interface](#SimplerInterfaces) than the mocked class provides. This pattern is also useful when the arguments are interesting, but match logic is substantially complex. You can leave the argument list unspecified and use SaveArg actions to [save the values for later verification](#SaveArgVerify). If you do that, you can easily differentiate calling the method the wrong number of times from calling it with the wrong arguments. ### Expecting Ordered Calls {#OrderedCalls} Although an `EXPECT_CALL()` statement defined later takes precedence when gMock tries to match a function call with an expectation, by default calls don't have to happen in the order `EXPECT_CALL()` statements are written. For example, if the arguments match the matchers in the second `EXPECT_CALL()`, but not those in the first and third, then the second expectation will be used. If you would rather have all calls occur in the order of the expectations, put the `EXPECT_CALL()` statements in a block where you define a variable of type `InSequence`: ```cpp using ::testing::_; using ::testing::InSequence; { InSequence s; EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(bar, DoThat(_)) .Times(2); EXPECT_CALL(foo, DoThis(6)); } ``` In this example, we expect a call to `foo.DoThis(5)`, followed by two calls to `bar.DoThat()` where the argument can be anything, which are in turn followed by a call to `foo.DoThis(6)`. If a call occurred out-of-order, gMock will report an error. ### Expecting Partially Ordered Calls {#PartialOrder} Sometimes requiring everything to occur in a predetermined order can lead to brittle tests. For example, we may care about `A` occurring before both `B` and `C`, but aren't interested in the relative order of `B` and `C`. In this case, the test should reflect our real intent, instead of being overly constraining. gMock allows you to impose an arbitrary DAG (directed acyclic graph) on the calls. One way to express the DAG is to use the [`After` clause](reference/mocking.md#EXPECT_CALL.After) of `EXPECT_CALL`. Another way is via the `InSequence()` clause (not the same as the `InSequence` class), which we borrowed from jMock 2. It's less flexible than `After()`, but more convenient when you have long chains of sequential calls, as it doesn't require you to come up with different names for the expectations in the chains. Here's how it works: If we view `EXPECT_CALL()` statements as nodes in a graph, and add an edge from node A to node B wherever A must occur before B, we can get a DAG. We use the term "sequence" to mean a directed path in this DAG. Now, if we decompose the DAG into sequences, we just need to know which sequences each `EXPECT_CALL()` belongs to in order to be able to reconstruct the original DAG. So, to specify the partial order on the expectations we need to do two things: first to define some `Sequence` objects, and then for each `EXPECT_CALL()` say which `Sequence` objects it is part of. Expectations in the same sequence must occur in the order they are written. For example, ```cpp using ::testing::Sequence; ... Sequence s1, s2; EXPECT_CALL(foo, A()) .InSequence(s1, s2); EXPECT_CALL(bar, B()) .InSequence(s1); EXPECT_CALL(bar, C()) .InSequence(s2); EXPECT_CALL(foo, D()) .InSequence(s2); ``` specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> C -> D`): ```text +---> B | A ---| | +---> C ---> D ``` This means that A must occur before B and C, and C must occur before D. There's no restriction about the order other than these. ### Controlling When an Expectation Retires When a mock method is called, gMock only considers expectations that are still active. An expectation is active when created, and becomes inactive (aka *retires*) when a call that has to occur later has occurred. For example, in ```cpp using ::testing::_; using ::testing::Sequence; ... Sequence s1, s2; EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 .Times(AnyNumber()) .InSequence(s1, s2); EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 .InSequence(s1); EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 .InSequence(s2); ``` as soon as either #2 or #3 is matched, #1 will retire. If a warning `"File too large."` is logged after this, it will be an error. Note that an expectation doesn't retire automatically when it's saturated. For example, ```cpp using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 ``` says that there will be exactly one warning with the message `"File too large."`. If the second warning contains this message too, #2 will match again and result in an upper-bound-violated error. If this is not what you want, you can ask an expectation to retire as soon as it becomes saturated: ```cpp using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 .RetiresOnSaturation(); ``` Here #2 can be used only once, so if you have two warnings with the message `"File too large."`, the first will match #2 and the second will match #1 - there will be no error. ## Using Actions ### Returning References from Mock Methods If a mock function's return type is a reference, you need to use `ReturnRef()` instead of `Return()` to return a result: ```cpp using ::testing::ReturnRef; class MockFoo : public Foo { public: MOCK_METHOD(Bar&, GetBar, (), (override)); }; ... MockFoo foo; Bar bar; EXPECT_CALL(foo, GetBar()) .WillOnce(ReturnRef(bar)); ... ``` ### Returning Live Values from Mock Methods The `Return(x)` action saves a copy of `x` when the action is created, and always returns the same value whenever it's executed. Sometimes you may want to instead return the *live* value of `x` (i.e. its value at the time when the action is *executed*.). Use either `ReturnRef()` or `ReturnPointee()` for this purpose. If the mock function's return type is a reference, you can do it using `ReturnRef(x)`, as shown in the previous recipe ("Returning References from Mock Methods"). However, gMock doesn't let you use `ReturnRef()` in a mock function whose return type is not a reference, as doing that usually indicates a user error. So, what shall you do? Though you may be tempted, DO NOT use `std::ref()`: ```cpp using ::testing::Return; class MockFoo : public Foo { public: MOCK_METHOD(int, GetValue, (), (override)); }; ... int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) .WillRepeatedly(Return(std::ref(x))); // Wrong! x = 42; EXPECT_EQ(foo.GetValue(), 42); ``` Unfortunately, it doesn't work here. The above code will fail with error: ```text Value of: foo.GetValue() Actual: 0 Expected: 42 ``` The reason is that `Return(*value*)` converts `value` to the actual return type of the mock function at the time when the action is *created*, not when it is *executed*. (This behavior was chosen for the action to be safe when `value` is a proxy object that references some temporary objects.) As a result, `std::ref(x)` is converted to an `int` value (instead of a `const int&`) when the expectation is set, and `Return(std::ref(x))` will always return 0. `ReturnPointee(pointer)` was provided to solve this problem specifically. It returns the value pointed to by `pointer` at the time the action is *executed*: ```cpp using ::testing::ReturnPointee; ... int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) .WillRepeatedly(ReturnPointee(&x)); // Note the & here. x = 42; EXPECT_EQ(foo.GetValue(), 42); // This will succeed now. ``` ### Combining Actions Want to do more than one thing when a function is called? That's fine. `DoAll()` allows you to do a sequence of actions every time. Only the return value of the last action in the sequence will be used. ```cpp using ::testing::_; using ::testing::DoAll; class MockFoo : public Foo { public: MOCK_METHOD(bool, Bar, (int n), (override)); }; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(DoAll(action_1, action_2, ... action_n)); ``` The return value of the last action **must** match the return type of the mocked method. In the example above, `action_n` could be `Return(true)`, or a lambda that returns a `bool`, but not `SaveArg`, which returns `void`. Otherwise the signature of `DoAll` would not match the signature expected by `WillOnce`, which is the signature of the mocked method, and it wouldn't compile. ### Verifying Complex Arguments {#SaveArgVerify} If you want to verify that a method is called with a particular argument but the match criteria is complex, it can be difficult to distinguish between cardinality failures (calling the method the wrong number of times) and argument match failures. Similarly, if you are matching multiple parameters, it may not be easy to distinguishing which argument failed to match. For example: ```cpp // Not ideal: this could fail because of a problem with arg1 or arg2, or maybe // just the method wasn't called. EXPECT_CALL(foo, SendValues(_, ElementsAre(1, 4, 4, 7), EqualsProto( ... ))); ``` You can instead save the arguments and test them individually: ```cpp EXPECT_CALL(foo, SendValues) .WillOnce(DoAll(SaveArg<1>(&actual_array), SaveArg<2>(&actual_proto))); ... run the test EXPECT_THAT(actual_array, ElementsAre(1, 4, 4, 7)); EXPECT_THAT(actual_proto, EqualsProto( ... )); ``` ### Mocking Side Effects {#MockingSideEffects} Sometimes a method exhibits its effect not via returning a value but via side effects. For example, it may change some global state or modify an output argument. To mock side effects, in general you can define your own action by implementing `::testing::ActionInterface`. If all you need to do is to change an output argument, the built-in `SetArgPointee()` action is convenient: ```cpp using ::testing::_; using ::testing::SetArgPointee; class MockMutator : public Mutator { public: MOCK_METHOD(void, Mutate, (bool mutate, int* value), (override)); ... } ... MockMutator mutator; EXPECT_CALL(mutator, Mutate(true, _)) .WillOnce(SetArgPointee<1>(5)); ``` In this example, when `mutator.Mutate()` is called, we will assign 5 to the `int` variable pointed to by argument #1 (0-based). `SetArgPointee()` conveniently makes an internal copy of the value you pass to it, removing the need to keep the value in scope and alive. The implication however is that the value must have a copy constructor and assignment operator. If the mock method also needs to return a value as well, you can chain `SetArgPointee()` with `Return()` using `DoAll()`, remembering to put the `Return()` statement last: ```cpp using ::testing::_; using ::testing::DoAll; using ::testing::Return; using ::testing::SetArgPointee; class MockMutator : public Mutator { public: ... MOCK_METHOD(bool, MutateInt, (int* value), (override)); } ... MockMutator mutator; EXPECT_CALL(mutator, MutateInt(_)) .WillOnce(DoAll(SetArgPointee<0>(5), Return(true))); ``` Note, however, that if you use the `ReturnOKWith()` method, it will override the values provided by `SetArgPointee()` in the response parameters of your function call. If the output argument is an array, use the `SetArrayArgument(first, last)` action instead. It copies the elements in source range `[first, last)` to the array pointed to by the `N`-th (0-based) argument: ```cpp using ::testing::NotNull; using ::testing::SetArrayArgument; class MockArrayMutator : public ArrayMutator { public: MOCK_METHOD(void, Mutate, (int* values, int num_values), (override)); ... } ... MockArrayMutator mutator; int values[5] = {1, 2, 3, 4, 5}; EXPECT_CALL(mutator, Mutate(NotNull(), 5)) .WillOnce(SetArrayArgument<0>(values, values + 5)); ``` This also works when the argument is an output iterator: ```cpp using ::testing::_; using ::testing::SetArrayArgument; class MockRolodex : public Rolodex { public: MOCK_METHOD(void, GetNames, (std::back_insert_iterator>), (override)); ... } ... MockRolodex rolodex; vector names = {"George", "John", "Thomas"}; EXPECT_CALL(rolodex, GetNames(_)) .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); ``` ### Changing a Mock Object's Behavior Based on the State If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: ```cpp using ::testing::InSequence; using ::testing::Return; ... { InSequence seq; EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(true)); EXPECT_CALL(my_mock, Flush()); EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(false)); } my_mock.FlushIfDirty(); ``` This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: ```cpp using ::testing::_; using ::testing::SaveArg; using ::testing::Return; ACTION_P(ReturnPointee, p) { return *p; } ... int previous_value = 0; EXPECT_CALL(my_mock, GetPrevValue) .WillRepeatedly(ReturnPointee(&previous_value)); EXPECT_CALL(my_mock, UpdateValue) .WillRepeatedly(SaveArg<0>(&previous_value)); my_mock.DoSomethingToUpdateValue(); ``` Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. ### Setting the Default Value for a Return Type {#DefaultValue} If a mock method's return type is a built-in C++ type or pointer, by default it will return 0 when invoked. Also, in C++ 11 and above, a mock method whose return type has a default constructor will return a default-constructed value by default. You only need to specify an action if this default value doesn't work for you. Sometimes, you may want to change this default value, or you may want to specify a default value for types gMock doesn't know about. You can do this using the `::testing::DefaultValue` class template: ```cpp using ::testing::DefaultValue; class MockFoo : public Foo { public: MOCK_METHOD(Bar, CalculateBar, (), (override)); }; ... Bar default_bar; // Sets the default return value for type Bar. DefaultValue::Set(default_bar); MockFoo foo; // We don't need to specify an action here, as the default // return value works for us. EXPECT_CALL(foo, CalculateBar()); foo.CalculateBar(); // This should return default_bar. // Unsets the default return value. DefaultValue::Clear(); ``` Please note that changing the default value for a type can make your tests hard to understand. We recommend you to use this feature judiciously. For example, you may want to make sure the `Set()` and `Clear()` calls are right next to the code that uses your mock. ### Setting the Default Actions for a Mock Method You've learned how to change the default value of a given type. However, this may be too coarse for your purpose: perhaps you have two mock methods with the same return type and you want them to have different behaviors. The `ON_CALL()` macro allows you to customize your mock's behavior at the method level: ```cpp using ::testing::_; using ::testing::AnyNumber; using ::testing::Gt; using ::testing::Return; ... ON_CALL(foo, Sign(_)) .WillByDefault(Return(-1)); ON_CALL(foo, Sign(0)) .WillByDefault(Return(0)); ON_CALL(foo, Sign(Gt(0))) .WillByDefault(Return(1)); EXPECT_CALL(foo, Sign(_)) .Times(AnyNumber()); foo.Sign(5); // This should return 1. foo.Sign(-9); // This should return -1. foo.Sign(0); // This should return 0. ``` As you may have guessed, when there are more than one `ON_CALL()` statements, the newer ones in the order take precedence over the older ones. In other words, the **last** one that matches the function arguments will be used. This matching order allows you to set up the common behavior in a mock object's constructor or the test fixture's set-up phase and specialize the mock's behavior later. Note that both `ON_CALL` and `EXPECT_CALL` have the same "later statements take precedence" rule, but they don't interact. That is, `EXPECT_CALL`s have their own precedence order distinct from the `ON_CALL` precedence order. ### Using Functions/Methods/Functors/Lambdas as Actions {#FunctionsAsActions} If the built-in actions don't suit you, you can use an existing callable (function, `std::function`, method, functor, lambda) as an action. ```cpp using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: MOCK_METHOD(int, Sum, (int x, int y), (override)); MOCK_METHOD(bool, ComplexJob, (int x), (override)); }; int CalculateSum(int x, int y) { return x + y; } int Sum3(int x, int y, int z) { return x + y + z; } class Helper { public: bool ComplexJob(int x); }; ... MockFoo foo; Helper helper; EXPECT_CALL(foo, Sum(_, _)) .WillOnce(&CalculateSum) .WillRepeatedly(Invoke(NewPermanentCallback(Sum3, 1))); EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(Invoke(&helper, &Helper::ComplexJob)) .WillOnce([] { return true; }) .WillRepeatedly([](int x) { return x > 0; }); foo.Sum(5, 6); // Invokes CalculateSum(5, 6). foo.Sum(2, 3); // Invokes Sum3(1, 2, 3). foo.ComplexJob(10); // Invokes helper.ComplexJob(10). foo.ComplexJob(-1); // Invokes the inline lambda. ``` The only requirement is that the type of the function, etc must be *compatible* with the signature of the mock function, meaning that the latter's arguments (if it takes any) can be implicitly converted to the corresponding arguments of the former, and the former's return type can be implicitly converted to that of the latter. So, you can invoke something whose type is *not* exactly the same as the mock function, as long as it's safe to do so - nice, huh? Note that: * The action takes ownership of the callback and will delete it when the action itself is destructed. * If the type of a callback is derived from a base callback type `C`, you need to implicitly cast it to `C` to resolve the overloading, e.g. ```cpp using ::testing::Invoke; ... ResultCallback* is_ok = ...; ... Invoke(is_ok) ...; // This works. BlockingClosure* done = new BlockingClosure; ... Invoke(implicit_cast(done)) ...; // The cast is necessary. ``` ### Using Functions with Extra Info as Actions The function or functor you call using `Invoke()` must have the same number of arguments as the mock function you use it for. Sometimes you may have a function that takes more arguments, and you are willing to pass in the extra arguments yourself to fill the gap. You can do this in gMock using callbacks with pre-bound arguments. Here's an example: ```cpp using ::testing::Invoke; class MockFoo : public Foo { public: MOCK_METHOD(char, DoThis, (int n), (override)); }; char SignOfSum(int x, int y) { const int sum = x + y; return (sum > 0) ? '+' : (sum < 0) ? '-' : '0'; } TEST_F(FooTest, Test) { MockFoo foo; EXPECT_CALL(foo, DoThis(2)) .WillOnce(Invoke(NewPermanentCallback(SignOfSum, 5))); EXPECT_EQ(foo.DoThis(2), '+'); // Invokes SignOfSum(5, 2). } ``` ### Invoking a Function/Method/Functor/Lambda/Callback Without Arguments `Invoke()` passes the mock function's arguments to the function, etc being invoked such that the callee has the full context of the call to work with. If the invoked function is not interested in some or all of the arguments, it can simply ignore them. Yet, a common pattern is that a test author wants to invoke a function without the arguments of the mock function. She could do that using a wrapper function that throws away the arguments before invoking an underlining nullary function. Needless to say, this can be tedious and obscures the intent of the test. There are two solutions to this problem. First, you can pass any callable of zero args as an action. Alternatively, use `InvokeWithoutArgs()`, which is like `Invoke()` except that it doesn't pass the mock function's arguments to the callee. Here's an example of each: ```cpp using ::testing::_; using ::testing::InvokeWithoutArgs; class MockFoo : public Foo { public: MOCK_METHOD(bool, ComplexJob, (int n), (override)); }; bool Job1() { ... } bool Job2(int n, char c) { ... } ... MockFoo foo; EXPECT_CALL(foo, ComplexJob(_)) .WillOnce([] { Job1(); }); .WillOnce(InvokeWithoutArgs(NewPermanentCallback(Job2, 5, 'a'))); foo.ComplexJob(10); // Invokes Job1(). foo.ComplexJob(20); // Invokes Job2(5, 'a'). ``` Note that: * The action takes ownership of the callback and will delete it when the action itself is destructed. * If the type of a callback is derived from a base callback type `C`, you need to implicitly cast it to `C` to resolve the overloading, e.g. ```cpp using ::testing::InvokeWithoutArgs; ... ResultCallback* is_ok = ...; ... InvokeWithoutArgs(is_ok) ...; // This works. BlockingClosure* done = ...; ... InvokeWithoutArgs(implicit_cast(done)) ...; // The cast is necessary. ``` ### Invoking an Argument of the Mock Function Sometimes a mock function will receive a function pointer, a functor (in other words, a "callable") as an argument, e.g. ```cpp class MockFoo : public Foo { public: MOCK_METHOD(bool, DoThis, (int n, (ResultCallback1* callback)), (override)); }; ``` and you may want to invoke this callable argument: ```cpp using ::testing::_; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(...); // Will execute callback->Run(5), where callback is the // second argument DoThis() receives. ``` {: .callout .note} NOTE: The section below is legacy documentation from before C++ had lambdas: Arghh, you need to refer to a mock function argument but C++ has no lambda (yet), so you have to define your own action. :-( Or do you really? Well, gMock has an action to solve *exactly* this problem: ```cpp InvokeArgument(arg_1, arg_2, ..., arg_m) ``` will invoke the `N`-th (0-based) argument the mock function receives, with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is a function pointer, a functor, or a callback. gMock handles them all. With that, you could write: ```cpp using ::testing::_; using ::testing::InvokeArgument; ... EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(InvokeArgument<1>(5)); // Will execute callback->Run(5), where callback is the // second argument DoThis() receives. ``` What if the callable takes an argument by reference? No problem - just wrap it inside `std::ref()`: ```cpp ... MOCK_METHOD(bool, Bar, ((ResultCallback2* callback)), (override)); ... using ::testing::_; using ::testing::InvokeArgument; ... MockFoo foo; Helper helper; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(InvokeArgument<0>(5, std::ref(helper))); // std::ref(helper) guarantees that a reference to helper, not a copy of // it, will be passed to the callback. ``` What if the callable takes an argument by reference and we do **not** wrap the argument in `std::ref()`? Then `InvokeArgument()` will *make a copy* of the argument, and pass a *reference to the copy*, instead of a reference to the original value, to the callable. This is especially handy when the argument is a temporary value: ```cpp ... MOCK_METHOD(bool, DoThat, (bool (*f)(const double& x, const string& s)), (override)); ... using ::testing::_; using ::testing::InvokeArgument; ... MockFoo foo; ... EXPECT_CALL(foo, DoThat(_)) .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); // Will execute (*f)(5.0, string("Hi")), where f is the function pointer // DoThat() receives. Note that the values 5.0 and string("Hi") are // temporary and dead once the EXPECT_CALL() statement finishes. Yet // it's fine to perform this action later, since a copy of the values // are kept inside the InvokeArgument action. ``` ### Ignoring an Action's Result Sometimes you have an action that returns *something*, but you need an action that returns `void` (perhaps you want to use it in a mock function that returns `void`, or perhaps it needs to be used in `DoAll()` and it's not the last in the list). `IgnoreResult()` lets you do that. For example: ```cpp using ::testing::_; using ::testing::DoAll; using ::testing::IgnoreResult; using ::testing::Return; int Process(const MyData& data); string DoSomething(); class MockFoo : public Foo { public: MOCK_METHOD(void, Abc, (const MyData& data), (override)); MOCK_METHOD(bool, Xyz, (), (override)); }; ... MockFoo foo; EXPECT_CALL(foo, Abc(_)) // .WillOnce(Invoke(Process)); // The above line won't compile as Process() returns int but Abc() needs // to return void. .WillOnce(IgnoreResult(Process)); EXPECT_CALL(foo, Xyz()) .WillOnce(DoAll(IgnoreResult(DoSomething), // Ignores the string DoSomething() returns. Return(true))); ``` Note that you **cannot** use `IgnoreResult()` on an action that already returns `void`. Doing so will lead to ugly compiler errors. ### Selecting an Action's Arguments {#SelectingArgs} Say you have a mock function `Foo()` that takes seven arguments, and you have a custom action that you want to invoke when `Foo()` is called. Trouble is, the custom action only wants three arguments: ```cpp using ::testing::_; using ::testing::Invoke; ... MOCK_METHOD(bool, Foo, (bool visible, const string& name, int x, int y, (const map>), double& weight, double min_weight, double max_wight)); ... bool IsVisibleInQuadrant1(bool visible, int x, int y) { return visible && x >= 0 && y >= 0; } ... EXPECT_CALL(mock, Foo) .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( ``` To please the compiler God, you need to define an "adaptor" that has the same signature as `Foo()` and calls the custom action with the right arguments: ```cpp using ::testing::_; using ::testing::Invoke; ... bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight) { return IsVisibleInQuadrant1(visible, x, y); } ... EXPECT_CALL(mock, Foo) .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. ``` But isn't this awkward? gMock provides a generic *action adaptor*, so you can spend your time minding more important business than writing your own adaptors. Here's the syntax: ```cpp WithArgs(action) ``` creates an action that passes the arguments of the mock function at the given indices (0-based) to the inner `action` and performs it. Using `WithArgs`, our original example can be written as: ```cpp using ::testing::_; using ::testing::Invoke; using ::testing::WithArgs; ... EXPECT_CALL(mock, Foo) .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); // No need to define your own adaptor. ``` For better readability, gMock also gives you: * `WithoutArgs(action)` when the inner `action` takes *no* argument, and * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes *one* argument. As you may have realized, `InvokeWithoutArgs(...)` is just syntactic sugar for `WithoutArgs(Invoke(...))`. Here are more tips: * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. * The types of the selected arguments do *not* have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. ### Ignoring Arguments in Action Functions The [selecting-an-action's-arguments](#SelectingArgs) recipe showed us one way to make a mock function and an action with incompatible argument lists fit together. The downside is that wrapping the action in `WithArgs<...>()` can get tedious for people writing the tests. If you are defining a function (or method, functor, lambda, callback) to be used with `Invoke*()`, and you are not interested in some of its arguments, an alternative to `WithArgs` is to declare the uninteresting arguments as `Unused`. This makes the definition less cluttered and less fragile in case the types of the uninteresting arguments change. It could also increase the chance the action function can be reused. For example, given ```cpp public: MOCK_METHOD(double, Foo, double(const string& label, double x, double y), (override)); MOCK_METHOD(double, Bar, (int index, double x, double y), (override)); ``` instead of ```cpp using ::testing::_; using ::testing::Invoke; double DistanceToOriginWithLabel(const string& label, double x, double y) { return sqrt(x*x + y*y); } double DistanceToOriginWithIndex(int index, double x, double y) { return sqrt(x*x + y*y); } ... EXPECT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOriginWithLabel)); EXPECT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOriginWithIndex)); ``` you could write ```cpp using ::testing::_; using ::testing::Invoke; using ::testing::Unused; double DistanceToOrigin(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXPECT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOrigin)); EXPECT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOrigin)); ``` ### Sharing Actions Just like matchers, a gMock action object consists of a pointer to a ref-counted implementation object. Therefore copying actions is also allowed and very efficient. When the last action that references the implementation object dies, the implementation object will be deleted. If you have some complex action that you want to use again and again, you may not have to build it from scratch every time. If the action doesn't have an internal state (i.e. if it always does the same thing no matter how many times it has been called), you can assign it to an action variable and use that variable repeatedly. For example: ```cpp using ::testing::Action; using ::testing::DoAll; using ::testing::Return; using ::testing::SetArgPointee; ... Action set_flag = DoAll(SetArgPointee<0>(5), Return(true)); ... use set_flag in .WillOnce() and .WillRepeatedly() ... ``` However, if the action has its own state, you may be surprised if you share the action object. Suppose you have an action factory `IncrementCounter(init)` which creates an action that increments and returns a counter whose initial value is `init`, using two actions created from the same expression and using a shared action will exhibit different behaviors. Example: ```cpp EXPECT_CALL(foo, DoThis()) .WillRepeatedly(IncrementCounter(0)); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(IncrementCounter(0)); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 1 - DoThat() uses a different // counter than DoThis()'s. ``` versus ```cpp using ::testing::Action; ... Action increment = IncrementCounter(0); EXPECT_CALL(foo, DoThis()) .WillRepeatedly(increment); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(increment); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 3 - the counter is shared. ``` ### Testing Asynchronous Behavior One oft-encountered problem with gMock is that it can be hard to test asynchronous behavior. Suppose you had a `EventQueue` class that you wanted to test, and you created a separate `EventDispatcher` interface so that you could easily mock it out. However, the implementation of the class fired all the events on a background thread, which made test timings difficult. You could just insert `sleep()` statements and hope for the best, but that makes your test behavior nondeterministic. A better way is to use gMock actions and `Notification` objects to force your asynchronous test to behave synchronously. ```cpp class MockEventDispatcher : public EventDispatcher { MOCK_METHOD(bool, DispatchEvent, (int32), (override)); }; TEST(EventQueueTest, EnqueueEventTest) { MockEventDispatcher mock_event_dispatcher; EventQueue event_queue(&mock_event_dispatcher); const int32 kEventId = 321; absl::Notification done; EXPECT_CALL(mock_event_dispatcher, DispatchEvent(kEventId)) .WillOnce([&done] { done.Notify(); }); event_queue.EnqueueEvent(kEventId); done.WaitForNotification(); } ``` In the example above, we set our normal gMock expectations, but then add an additional action to notify the `Notification` object. Now we can just call `Notification::WaitForNotification()` in the main thread to wait for the asynchronous call to finish. After that, our test suite is complete and we can safely exit. {: .callout .note} Note: this example has a downside: namely, if the expectation is not satisfied, our test will run forever. It will eventually time-out and fail, but it will take longer and be slightly harder to debug. To alleviate this problem, you can use `WaitForNotificationWithTimeout(ms)` instead of `WaitForNotification()`. ## Misc Recipes on Using gMock ### Mocking Methods That Use Move-Only Types C++11 introduced *move-only types*. A move-only-typed value can be moved from one object to another, but cannot be copied. `std::unique_ptr` is probably the most commonly used move-only type. Mocking a method that takes and/or returns move-only types presents some challenges, but nothing insurmountable. This recipe shows you how you can do it. Note that the support for move-only method arguments was only introduced to gMock in April 2017; in older code, you may find more complex [workarounds](#LegacyMoveOnly) for lack of this feature. Let’s say we are working on a fictional project that lets one post and share snippets called “buzzes”. Your code uses these types: ```cpp enum class AccessLevel { kInternal, kPublic }; class Buzz { public: explicit Buzz(AccessLevel access) { ... } ... }; class Buzzer { public: virtual ~Buzzer() {} virtual std::unique_ptr MakeBuzz(StringPiece text) = 0; virtual bool ShareBuzz(std::unique_ptr buzz, int64_t timestamp) = 0; ... }; ``` A `Buzz` object represents a snippet being posted. A class that implements the `Buzzer` interface is capable of creating and sharing `Buzz`es. Methods in `Buzzer` may return a `unique_ptr` or take a `unique_ptr`. Now we need to mock `Buzzer` in our tests. To mock a method that accepts or returns move-only types, you just use the familiar `MOCK_METHOD` syntax as usual: ```cpp class MockBuzzer : public Buzzer { public: MOCK_METHOD(std::unique_ptr, MakeBuzz, (StringPiece text), (override)); MOCK_METHOD(bool, ShareBuzz, (std::unique_ptr buzz, int64_t timestamp), (override)); }; ``` Now that we have the mock class defined, we can use it in tests. In the following code examples, we assume that we have defined a `MockBuzzer` object named `mock_buzzer_`: ```cpp MockBuzzer mock_buzzer_; ``` First let’s see how we can set expectations on the `MakeBuzz()` method, which returns a `unique_ptr`. As usual, if you set an expectation without an action (i.e. the `.WillOnce()` or `.WillRepeatedly()` clause), when that expectation fires, the default action for that method will be taken. Since `unique_ptr<>` has a default constructor that returns a null `unique_ptr`, that’s what you’ll get if you don’t specify an action: ```cpp using ::testing::IsNull; ... // Use the default action. EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")); // Triggers the previous EXPECT_CALL. EXPECT_THAT(mock_buzzer_.MakeBuzz("hello"), IsNull()); ``` If you are not happy with the default action, you can tweak it as usual; see [Setting Default Actions](#OnCall). If you just need to return a move-only value, you can use it in combination with `WillOnce`. For example: ```cpp EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")) .WillOnce(Return(std::make_unique(AccessLevel::kInternal))); EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("hello")); ``` Quiz time! What do you think will happen if a `Return` action is performed more than once (e.g. you write `... .WillRepeatedly(Return(std::move(...)));`)? Come think of it, after the first time the action runs, the source value will be consumed (since it’s a move-only value), so the next time around, there’s no value to move from -- you’ll get a run-time error that `Return(std::move(...))` can only be run once. If you need your mock method to do more than just moving a pre-defined value, remember that you can always use a lambda or a callable object, which can do pretty much anything you want: ```cpp EXPECT_CALL(mock_buzzer_, MakeBuzz("x")) .WillRepeatedly([](StringPiece text) { return std::make_unique(AccessLevel::kInternal); }); EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); ``` Every time this `EXPECT_CALL` fires, a new `unique_ptr` will be created and returned. You cannot do this with `Return(std::make_unique<...>(...))`. That covers returning move-only values; but how do we work with methods accepting move-only arguments? The answer is that they work normally, although some actions will not compile when any of method's arguments are move-only. You can always use `Return`, or a [lambda or functor](#FunctionsAsActions): ```cpp using ::testing::Unused; EXPECT_CALL(mock_buzzer_, ShareBuzz(NotNull(), _)).WillOnce(Return(true)); EXPECT_TRUE(mock_buzzer_.ShareBuzz(std::make_unique(AccessLevel::kInternal)), 0); EXPECT_CALL(mock_buzzer_, ShareBuzz(_, _)).WillOnce( [](std::unique_ptr buzz, Unused) { return buzz != nullptr; }); EXPECT_FALSE(mock_buzzer_.ShareBuzz(nullptr, 0)); ``` Many built-in actions (`WithArgs`, `WithoutArgs`,`DeleteArg`, `SaveArg`, ...) could in principle support move-only arguments, but the support for this is not implemented yet. If this is blocking you, please file a bug. A few actions (e.g. `DoAll`) copy their arguments internally, so they can never work with non-copyable objects; you'll have to use functors instead. #### Legacy workarounds for move-only types {#LegacyMoveOnly} Support for move-only function arguments was only introduced to gMock in April of 2017. In older code, you may encounter the following workaround for the lack of this feature (it is no longer necessary - we're including it just for reference): ```cpp class MockBuzzer : public Buzzer { public: MOCK_METHOD(bool, DoShareBuzz, (Buzz* buzz, Time timestamp)); bool ShareBuzz(std::unique_ptr buzz, Time timestamp) override { return DoShareBuzz(buzz.get(), timestamp); } }; ``` The trick is to delegate the `ShareBuzz()` method to a mock method (let’s call it `DoShareBuzz()`) that does not take move-only parameters. Then, instead of setting expectations on `ShareBuzz()`, you set them on the `DoShareBuzz()` mock method: ```cpp MockBuzzer mock_buzzer_; EXPECT_CALL(mock_buzzer_, DoShareBuzz(NotNull(), _)); // When one calls ShareBuzz() on the MockBuzzer like this, the call is // forwarded to DoShareBuzz(), which is mocked. Therefore this statement // will trigger the above EXPECT_CALL. mock_buzzer_.ShareBuzz(std::make_unique(AccessLevel::kInternal), 0); ``` ### Making the Compilation Faster Believe it or not, the *vast majority* of the time spent on compiling a mock class is in generating its constructor and destructor, as they perform non-trivial tasks (e.g. verification of the expectations). What's more, mock methods with different signatures have different types and thus their constructors/destructors need to be generated by the compiler separately. As a result, if you mock many different types of methods, compiling your mock class can get really slow. If you are experiencing slow compilation, you can move the definition of your mock class' constructor and destructor out of the class body and into a `.cc` file. This way, even if you `#include` your mock class in N files, the compiler only needs to generate its constructor and destructor once, resulting in a much faster compilation. Let's illustrate the idea using an example. Here's the definition of a mock class before applying this recipe: ```cpp // File mock_foo.h. ... class MockFoo : public Foo { public: // Since we don't declare the constructor or the destructor, // the compiler will generate them in every translation unit // where this mock class is used. MOCK_METHOD(int, DoThis, (), (override)); MOCK_METHOD(bool, DoThat, (const char* str), (override)); ... more mock methods ... }; ``` After the change, it would look like: ```cpp // File mock_foo.h. ... class MockFoo : public Foo { public: // The constructor and destructor are declared, but not defined, here. MockFoo(); virtual ~MockFoo(); MOCK_METHOD(int, DoThis, (), (override)); MOCK_METHOD(bool, DoThat, (const char* str), (override)); ... more mock methods ... }; ``` and ```cpp // File mock_foo.cc. #include "path/to/mock_foo.h" // The definitions may appear trivial, but the functions actually do a // lot of things through the constructors/destructors of the member // variables used to implement the mock methods. MockFoo::MockFoo() {} MockFoo::~MockFoo() {} ``` ### Forcing a Verification When it's being destroyed, your friendly mock object will automatically verify that all expectations on it have been satisfied, and will generate googletest failures if not. This is convenient as it leaves you with one less thing to worry about. That is, unless you are not sure if your mock object will be destroyed. How could it be that your mock object won't eventually be destroyed? Well, it might be created on the heap and owned by the code you are testing. Suppose there's a bug in that code and it doesn't delete the mock object properly - you could end up with a passing test when there's actually a bug. Using a heap checker is a good idea and can alleviate the concern, but its implementation is not 100% reliable. So, sometimes you do want to *force* gMock to verify a mock object before it is (hopefully) destructed. You can do this with `Mock::VerifyAndClearExpectations(&mock_object)`: ```cpp TEST(MyServerTest, ProcessesRequest) { using ::testing::Mock; MockFoo* const foo = new MockFoo; EXPECT_CALL(*foo, ...)...; // ... other expectations ... // server now owns foo. MyServer server(foo); server.ProcessRequest(...); // In case that server's destructor will forget to delete foo, // this will verify the expectations anyway. Mock::VerifyAndClearExpectations(foo); } // server is destroyed when it goes out of scope here. ``` {: .callout .tip} **Tip:** The `Mock::VerifyAndClearExpectations()` function returns a `bool` to indicate whether the verification was successful (`true` for yes), so you can wrap that function call inside a `ASSERT_TRUE()` if there is no point going further when the verification has failed. Do not set new expectations after verifying and clearing a mock after its use. Setting expectations after code that exercises the mock has undefined behavior. See [Using Mocks in Tests](gmock_for_dummies.md#using-mocks-in-tests) for more information. ### Using Checkpoints {#UsingCheckPoints} Sometimes you might want to test a mock object's behavior in phases whose sizes are each manageable, or you might want to set more detailed expectations about which API calls invoke which mock functions. A technique you can use is to put the expectations in a sequence and insert calls to a dummy "checkpoint" function at specific places. Then you can verify that the mock function calls do happen at the right time. For example, if you are exercising the code: ```cpp Foo(1); Foo(2); Foo(3); ``` and want to verify that `Foo(1)` and `Foo(3)` both invoke `mock.Bar("a")`, but `Foo(2)` doesn't invoke anything, you can write: ```cpp using ::testing::MockFunction; TEST(FooTest, InvokesBarCorrectly) { MyMock mock; // Class MockFunction has exactly one mock method. It is named // Call() and has type F. MockFunction check; { InSequence s; EXPECT_CALL(mock, Bar("a")); EXPECT_CALL(check, Call("1")); EXPECT_CALL(check, Call("2")); EXPECT_CALL(mock, Bar("a")); } Foo(1); check.Call("1"); Foo(2); check.Call("2"); Foo(3); } ``` The expectation spec says that the first `Bar("a")` call must happen before checkpoint "1", the second `Bar("a")` call must happen after checkpoint "2", and nothing should happen between the two checkpoints. The explicit checkpoints make it clear which `Bar("a")` is called by which call to `Foo()`. ### Mocking Destructors Sometimes you want to make sure a mock object is destructed at the right time, e.g. after `bar->A()` is called but before `bar->B()` is called. We already know that you can specify constraints on the [order](#OrderedCalls) of mock function calls, so all we need to do is to mock the destructor of the mock function. This sounds simple, except for one problem: a destructor is a special function with special syntax and special semantics, and the `MOCK_METHOD` macro doesn't work for it: ```cpp MOCK_METHOD(void, ~MockFoo, ()); // Won't compile! ``` The good news is that you can use a simple pattern to achieve the same effect. First, add a mock function `Die()` to your mock class and call it in the destructor, like this: ```cpp class MockFoo : public Foo { ... // Add the following two lines to the mock class. MOCK_METHOD(void, Die, ()); ~MockFoo() override { Die(); } }; ``` (If the name `Die()` clashes with an existing symbol, choose another name.) Now, we have translated the problem of testing when a `MockFoo` object dies to testing when its `Die()` method is called: ```cpp MockFoo* foo = new MockFoo; MockBar* bar = new MockBar; ... { InSequence s; // Expects *foo to die after bar->A() and before bar->B(). EXPECT_CALL(*bar, A()); EXPECT_CALL(*foo, Die()); EXPECT_CALL(*bar, B()); } ``` And that's that. ### Using gMock and Threads {#UsingThreads} In a **unit** test, it's best if you could isolate and test a piece of code in a single-threaded context. That avoids race conditions and dead locks, and makes debugging your test much easier. Yet most programs are multi-threaded, and sometimes to test something we need to pound on it from more than one thread. gMock works for this purpose too. Remember the steps for using a mock: 1. Create a mock object `foo`. 2. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. 3. The code under test calls methods of `foo`. 4. Optionally, verify and reset the mock. 5. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. If you follow the following simple rules, your mocks and threads can live happily together: * Execute your *test code* (as opposed to the code being tested) in *one* thread. This makes your test easy to follow. * Obviously, you can do step #1 without locking. * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. gMock takes care of the locking, so you don't have to do any - unless required by your test logic. If you violate the rules (for example, if you set expectations on a mock while another thread is calling its methods), you get undefined behavior. That's not fun, so don't do it. gMock guarantees that the action for a mock function is done in the same thread that called the mock function. For example, in ```cpp EXPECT_CALL(mock, Foo(1)) .WillOnce(action1); EXPECT_CALL(mock, Foo(2)) .WillOnce(action2); ``` if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, gMock will execute `action1` in thread 1 and `action2` in thread 2. gMock does *not* impose a sequence on actions performed in different threads (doing so may create deadlocks as the actions may need to cooperate). This means that the execution of `action1` and `action2` in the above example *may* interleave. If this is a problem, you should add proper synchronization logic to `action1` and `action2` to make the test thread-safe. Also, remember that `DefaultValue` is a global resource that potentially affects *all* living mock objects in your program. Naturally, you won't want to mess with it from multiple threads or when there still are mocks in action. ### Controlling How Much Information gMock Prints When gMock sees something that has the potential of being an error (e.g. a mock function with no expectation is called, a.k.a. an uninteresting call, which is allowed but perhaps you forgot to explicitly ban the call), it prints some warning messages, including the arguments of the function, the return value, and the stack trace. Hopefully this will remind you to take a look and see if there is indeed a problem. Sometimes you are confident that your tests are correct and may not appreciate such friendly messages. Some other times, you are debugging your tests or learning about the behavior of the code you are testing, and wish you could observe every mock call that happens (including argument values, the return value, and the stack trace). Clearly, one size doesn't fit all. You can control how much gMock tells you using the `--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string with three possible values: * `info`: gMock will print all informational messages, warnings, and errors (most verbose). At this setting, gMock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. It will include a stack trace in "uninteresting call" warnings. * `warning`: gMock will print both warnings and errors (less verbose); it will omit the stack traces in "uninteresting call" warnings. This is the default. * `error`: gMock will print errors only (least verbose). Alternatively, you can adjust the value of that flag from within your tests like so: ```cpp ::testing::FLAGS_gmock_verbose = "error"; ``` If you find gMock printing too many stack frames with its informational or warning messages, remember that you can control their amount with the `--gtest_stack_trace_depth=max_depth` flag. Now, judiciously use the right flag to enable gMock serve you better! ### Gaining Super Vision into Mock Calls You have a test using gMock. It fails: gMock tells you some expectations aren't satisfied. However, you aren't sure why: Is there a typo somewhere in the matchers? Did you mess up the order of the `EXPECT_CALL`s? Or is the code under test doing something wrong? How can you find out the cause? Won't it be nice if you have X-ray vision and can actually see the trace of all `EXPECT_CALL`s and mock method calls as they are made? For each call, would you like to see its actual argument values and which `EXPECT_CALL` gMock thinks it matches? If you still need some help to figure out who made these calls, how about being able to see the complete stack trace at each mock call? You can unlock this power by running your test with the `--gmock_verbose=info` flag. For example, given the test program: ```cpp #include using ::testing::_; using ::testing::HasSubstr; using ::testing::Return; class MockFoo { public: MOCK_METHOD(void, F, (const string& x, const string& y)); }; TEST(Foo, Bar) { MockFoo mock; EXPECT_CALL(mock, F(_, _)).WillRepeatedly(Return()); EXPECT_CALL(mock, F("a", "b")); EXPECT_CALL(mock, F("c", HasSubstr("d"))); mock.F("a", "good"); mock.F("a", "b"); } ``` if you run it with `--gmock_verbose=info`, you will see this output: ```shell [ RUN ] Foo.Bar foo_test.cc:14: EXPECT_CALL(mock, F(_, _)) invoked Stack trace: ... foo_test.cc:15: EXPECT_CALL(mock, F("a", "b")) invoked Stack trace: ... foo_test.cc:16: EXPECT_CALL(mock, F("c", HasSubstr("d"))) invoked Stack trace: ... foo_test.cc:14: Mock function call matches EXPECT_CALL(mock, F(_, _))... Function call: F(@0x7fff7c8dad40"a",@0x7fff7c8dad10"good") Stack trace: ... foo_test.cc:15: Mock function call matches EXPECT_CALL(mock, F("a", "b"))... Function call: F(@0x7fff7c8dada0"a",@0x7fff7c8dad70"b") Stack trace: ... foo_test.cc:16: Failure Actual function call count doesn't match EXPECT_CALL(mock, F("c", HasSubstr("d")))... Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] Foo.Bar ``` Suppose the bug is that the `"c"` in the third `EXPECT_CALL` is a typo and should actually be `"a"`. With the above message, you should see that the actual `F("a", "good")` call is matched by the first `EXPECT_CALL`, not the third as you thought. From that it should be obvious that the third `EXPECT_CALL` is written wrong. Case solved. If you are interested in the mock call trace but not the stack traces, you can combine `--gmock_verbose=info` with `--gtest_stack_trace_depth=0` on the test command line. ### Running Tests in Emacs If you build and run your tests in Emacs using the `M-x google-compile` command (as many googletest users do), the source file locations of gMock and googletest errors will be highlighted. Just press `` on one of them and you'll be taken to the offending line. Or, you can just type `C-x`` to jump to the next error. To make it even easier, you can add the following lines to your `~/.emacs` file: ```text (global-set-key "\M-m" 'google-compile) ; m is for make (global-set-key [M-down] 'next-error) (global-set-key [M-up] '(lambda () (interactive) (next-error -1))) ``` Then you can type `M-m` to start a build (if you want to run the test as well, just make sure `foo_test.run` or `runtests` is in the build command you supply after typing `M-m`), or `M-up`/`M-down` to move back and forth between errors. ## Extending gMock ### Writing New Matchers Quickly {#NewMatchers} {: .callout .warning} WARNING: gMock does not guarantee when or how many times a matcher will be invoked. Therefore, all matchers must be functionally pure. See [this section](#PureMatchers) for more details. The `MATCHER*` family of macros can be used to define custom matchers easily. The syntax: ```cpp MATCHER(name, description_string_expression) { statements; } ``` will define a matcher with the given name that executes the statements, which must return a `bool` to indicate if the match succeeds. Inside the statements, you can refer to the value being matched by `arg`, and refer to its type by `arg_type`. The *description string* is a `string`-typed expression that documents what the matcher does, and is used to generate the failure message when the match fails. It can (and should) reference the special `bool` variable `negation`, and should evaluate to the description of the matcher when `negation` is `false`, or that of the matcher's negation when `negation` is `true`. For convenience, we allow the description string to be empty (`""`), in which case gMock will use the sequence of words in the matcher name as the description. #### Basic Example ```cpp MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } ``` allows you to write ```cpp // Expects mock_foo.Bar(n) to be called where n is divisible by 7. EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); ``` or, ```cpp using ::testing::Not; ... // Verifies that a value is divisible by 7 and the other is not. EXPECT_THAT(some_expression, IsDivisibleBy7()); EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); ``` If the above assertions fail, they will print something like: ```shell Value of: some_expression Expected: is divisible by 7 Actual: 27 ... Value of: some_other_expression Expected: not (is divisible by 7) Actual: 21 ``` where the descriptions `"is divisible by 7"` and `"not (is divisible by 7)"` are automatically calculated from the matcher name `IsDivisibleBy7`. #### Adding Custom Failure Messages As you may have noticed, the auto-generated descriptions (especially those for the negation) may not be so great. You can always override them with a `string` expression of your own: ```cpp MATCHER(IsDivisibleBy7, absl::StrCat(negation ? "isn't" : "is", " divisible by 7")) { return (arg % 7) == 0; } ``` Optionally, you can stream additional information to a hidden argument named `result_listener` to explain the match result. For example, a better definition of `IsDivisibleBy7` is: ```cpp MATCHER(IsDivisibleBy7, "") { if ((arg % 7) == 0) return true; *result_listener << "the remainder is " << (arg % 7); return false; } ``` With this definition, the above assertion will give a better message: ```shell Value of: some_expression Expected: is divisible by 7 Actual: 27 (the remainder is 6) ``` #### Using EXPECT_ Statements in Matchers You can also use `EXPECT_...` statements inside custom matcher definitions. In many cases, this allows you to write your matcher more concisely while still providing an informative error message. For example: ```cpp MATCHER(IsDivisibleBy7, "") { const auto remainder = arg % 7; EXPECT_EQ(remainder, 0); return true; } ``` If you write a test that includes the line `EXPECT_THAT(27, IsDivisibleBy7());`, you will get an error something like the following: ```shell Expected equality of these values: remainder Which is: 6 0 ``` #### `MatchAndExplain` You should let `MatchAndExplain()` print *any additional information* that can help a user understand the match result. Note that it should explain why the match succeeds in case of a success (unless it's obvious) - this is useful when the matcher is used inside `Not()`. There is no need to print the argument value itself, as gMock already prints it for you. #### Argument Types The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. ### Writing New Parameterized Matchers Quickly Sometimes you'll want to define a matcher that has parameters. For that you can use the macro: ```cpp MATCHER_P(name, param_name, description_string) { statements; } ``` where the description string can be either `""` or a `string` expression that references `negation` and `param_name`. For example: ```cpp MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } ``` will allow you to write: ```cpp EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); ``` which may lead to this message (assuming `n` is 10): ```shell Value of: Blah("a") Expected: has absolute value 10 Actual: -9 ``` Note that both the matcher description and its parameter are printed, making the message human-friendly. In the matcher definition body, you can write `foo_type` to reference the type of a parameter named `foo`. For example, in the body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write `value_type` to refer to the type of `value`. gMock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to `MATCHER_P10` to support multi-parameter matchers: ```cpp MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } ``` Please note that the custom description string is for a particular *instance* of the matcher, where the parameters have been bound to actual values. Therefore usually you'll want the parameter values to be part of the description. gMock lets you do that by referencing the matcher parameters in the description string expression. For example, ```cpp using ::testing::PrintToString; MATCHER_P2(InClosedRange, low, hi, absl::StrFormat("%s in range [%s, %s]", negation ? "isn't" : "is", PrintToString(low), PrintToString(hi))) { return low <= arg && arg <= hi; } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the message: ```shell Expected: is in range [4, 6] ``` If you specify `""` as the description, the failure message will contain the sequence of words in the matcher name followed by the parameter values printed as a tuple. For example, ```cpp MATCHER_P2(InClosedRange, low, hi, "") { ... } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the text: ```shell Expected: in closed range (4, 6) ``` For the purpose of typing, you can view ```cpp MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } ``` as shorthand for ```cpp template FooMatcherPk Foo(p1_type p1, ..., pk_type pk) { ... } ``` When you write `Foo(v1, ..., vk)`, the compiler infers the types of the parameters `v1`, ..., and `vk` for you. If you are not happy with the result of the type inference, you can specify the types by explicitly instantiating the template, as in `Foo(5, false)`. As said earlier, you don't get to (or need to) specify `arg_type` as that's determined by the context in which the matcher is used. You can assign the result of expression `Foo(p1, ..., pk)` to a variable of type `FooMatcherPk`. This can be useful when composing matchers. Matchers that don't have a parameter or have only one parameter have special types: you can assign `Foo()` to a `FooMatcher`-typed variable, and assign `Foo(p)` to a `FooMatcherP`-typed variable. While you can instantiate a matcher template with reference types, passing the parameters by pointer usually makes your code more readable. If, however, you still want to pass a parameter by reference, be aware that in the failure message generated by the matcher you will see the value of the referenced object but not its address. You can overload matchers with different numbers of parameters: ```cpp MATCHER_P(Blah, a, description_string_1) { ... } MATCHER_P2(Blah, a, b, description_string_2) { ... } ``` While it's tempting to always use the `MATCHER*` macros when defining a new matcher, you should also consider implementing the matcher interface directly instead (see the recipes that follow), especially if you need to use the matcher a lot. While these approaches require more work, they give you more control on the types of the value being matched and the matcher parameters, which in general leads to better compiler error messages that pay off in the long run. They also allow overloading matchers based on parameter types (as opposed to just based on the number of parameters). ### Writing New Monomorphic Matchers A matcher of type `testing::Matcher` implements the matcher interface for `T` and does two things: it tests whether a value of type `T` matches the matcher, and can describe what kind of values it matches. The latter ability is used for generating readable error messages when expectations are violated. Some matchers can even explain why it matches or doesn't match a certain value, which can be helpful when the reason isn't obvious. Because a matcher of type `testing::Matcher` for a particular type `T` can only be used to match a value of type `T`, we call it "monomorphic." A matcher of `T` must declare a typedef like: ```cpp using is_gtest_matcher = void; ``` and supports the following operations: ```cpp // Match a value and optionally explain into an ostream. bool matched = matcher.MatchAndExplain(value, maybe_os); // where `value` is of type `T` and // `maybe_os` is of type `std::ostream*`, where it can be null if the caller // is not interested in there textual explanation. matcher.DescribeTo(os); matcher.DescribeNegationTo(os); // where `os` is of type `std::ostream*`. ``` If you need a custom matcher but `Truly()` is not a good option (for example, you may not be happy with the way `Truly(predicate)` describes itself, or you may want your matcher to be polymorphic as `Eq(value)` is), you can define a matcher to do whatever you want in two steps: first implement the matcher interface, and then define a factory function to create a matcher instance. The second step is not strictly needed but it makes the syntax of using the matcher nicer. For example, you can define a matcher to test whether an `int` is divisible by 7 and then use it like this: ```cpp using ::testing::Matcher; class DivisibleBy7Matcher { public: using is_gtest_matcher = void; bool MatchAndExplain(int n, std::ostream*) const { return (n % 7) == 0; } void DescribeTo(std::ostream* os) const { *os << "is divisible by 7"; } void DescribeNegationTo(std::ostream* os) const { *os << "is not divisible by 7"; } }; Matcher DivisibleBy7() { return DivisibleBy7Matcher(); } ... EXPECT_CALL(foo, Bar(DivisibleBy7())); ``` You may improve the matcher message by streaming additional information to the `os` argument in `MatchAndExplain()`: ```cpp class DivisibleBy7Matcher { public: bool MatchAndExplain(int n, std::ostream* os) const { const int remainder = n % 7; if (remainder != 0 && os != nullptr) { *os << "the remainder is " << remainder; } return remainder == 0; } ... }; ``` Then, `EXPECT_THAT(x, DivisibleBy7());` may generate a message like this: ```shell Value of: x Expected: is divisible by 7 Actual: 23 (the remainder is 2) ``` {: .callout .tip} Tip: for convenience, `MatchAndExplain()` can take a `MatchResultListener*` instead of `std::ostream*`. ### Writing New Polymorphic Matchers Unlike a monomorphic matcher, which can only be used to match a value of a particular type, a *polymorphic* matcher is one that can be used to match values of multiple types. For example, `Eq(5)` is a polymorhpic matcher as it can be used to match an `int`, a `double`, a `float`, and so on. You should think of a polymorphic matcher as a *matcher factory* as opposed to a `testing::Matcher` - itself is not an actual matcher, but can be implicitly converted to a `testing::Matcher` depending on the context. Expanding what we learned above to polymorphic matchers is now as simple as adding templates in the right place. ```cpp class NotNullMatcher { public: using is_gtest_matcher = void; // To implement a polymorphic matcher, we just need to make MatchAndExplain a // template on its first argument. // In this example, we want to use NotNull() with any pointer, so // MatchAndExplain() accepts a pointer of any type as its first argument. // In general, you can define MatchAndExplain() as an ordinary method or // a method template, or even overload it. template bool MatchAndExplain(T* p, std::ostream*) const { return p != nullptr; } // Describes the property of a value matching this matcher. void DescribeTo(std::ostream* os) const { *os << "is not NULL"; } // Describes the property of a value NOT matching this matcher. void DescribeNegationTo(std::ostream* os) const { *os << "is NULL"; } }; NotNullMatcher NotNull() { return NotNullMatcher(); } ... EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. ``` ### Legacy Matcher Implementation Defining matchers used to be somewhat more complicated, in which it required several supporting classes and virtual functions. To implement a matcher for type `T` using the legacy API you have to derive from `MatcherInterface` and call `MakeMatcher` to construct the object. The interface looks like this: ```cpp class MatchResultListener { public: ... // Streams x to the underlying ostream; does nothing if the ostream // is NULL. template MatchResultListener& operator<<(const T& x); // Returns the underlying ostream. std::ostream* stream(); }; template class MatcherInterface { public: virtual ~MatcherInterface(); // Returns true if and only if the matcher matches x; also explains the match // result to 'listener'. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; // Describes this matcher to an ostream. virtual void DescribeTo(std::ostream* os) const = 0; // Describes the negation of this matcher to an ostream. virtual void DescribeNegationTo(std::ostream* os) const; }; ``` Fortunately, most of the time you can define a polymorphic matcher easily with the help of `MakePolymorphicMatcher()`. Here's how you can define `NotNull()` as an example: ```cpp using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; using ::testing::PolymorphicMatcher; class NotNullMatcher { public: // To implement a polymorphic matcher, first define a COPYABLE class // that has three members MatchAndExplain(), DescribeTo(), and // DescribeNegationTo(), like the following. // In this example, we want to use NotNull() with any pointer, so // MatchAndExplain() accepts a pointer of any type as its first argument. // In general, you can define MatchAndExplain() as an ordinary method or // a method template, or even overload it. template bool MatchAndExplain(T* p, MatchResultListener* /* listener */) const { return p != NULL; } // Describes the property of a value matching this matcher. void DescribeTo(std::ostream* os) const { *os << "is not NULL"; } // Describes the property of a value NOT matching this matcher. void DescribeNegationTo(std::ostream* os) const { *os << "is NULL"; } }; // To construct a polymorphic matcher, pass an instance of the class // to MakePolymorphicMatcher(). Note the return type. PolymorphicMatcher NotNull() { return MakePolymorphicMatcher(NotNullMatcher()); } ... EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. ``` {: .callout .note} **Note:** Your polymorphic matcher class does **not** need to inherit from `MatcherInterface` or any other class, and its methods do **not** need to be virtual. Like in a monomorphic matcher, you may explain the match result by streaming additional information to the `listener` argument in `MatchAndExplain()`. ### Implementing Composite Matchers {#CompositeMatchers} Sometimes we want to define a matcher that takes other matchers as parameters. For example, `DistanceFrom(target, m)` is a polymorphic matcher that takes a matcher `m` as a parameter. It tests that the distance from `target` to the value being matched satisfies sub-matcher `m`. If you are implementing such a composite matcher, you'll need to generate the description of the matcher based on the description(s) of its sub-matcher(s). You can see the implementation of `DistanceFrom()` in `googlemock/include/gmock/gmock-matchers.h` for an example. In particular, pay attention to `DistanceFromMatcherImpl`. Notice that it stores the sub-matcher as a `const Matcher distance_matcher_` instead of a polymorphic matcher - this allows it to call `distance_matcher_.DescribeTo(os)` to describe the sub-matcher. If the sub-matcher is stored as a polymorphic matcher instead, it would not be possible to get its description as in general polymorphic matchers don't know how to describe themselves - they are matcher factories instead of actual matchers; only after being converted to `Matcher` can they be described. ### Writing New Cardinalities A cardinality is used in `Times()` to tell gMock how many times you expect a call to occur. It doesn't have to be exact. For example, you can say `AtLeast(5)` or `Between(2, 4)`. If the [built-in set](gmock_cheat_sheet.md#CardinalityList) of cardinalities doesn't suit you, you are free to define your own by implementing the following interface (in namespace `testing`): ```cpp class CardinalityInterface { public: virtual ~CardinalityInterface(); // Returns true if and only if call_count calls will satisfy this cardinality. virtual bool IsSatisfiedByCallCount(int call_count) const = 0; // Returns true if and only if call_count calls will saturate this // cardinality. virtual bool IsSaturatedByCallCount(int call_count) const = 0; // Describes self to an ostream. virtual void DescribeTo(std::ostream* os) const = 0; }; ``` For example, to specify that a call must occur even number of times, you can write ```cpp using ::testing::Cardinality; using ::testing::CardinalityInterface; using ::testing::MakeCardinality; class EvenNumberCardinality : public CardinalityInterface { public: bool IsSatisfiedByCallCount(int call_count) const override { return (call_count % 2) == 0; } bool IsSaturatedByCallCount(int call_count) const override { return false; } void DescribeTo(std::ostream* os) const { *os << "called even number of times"; } }; Cardinality EvenNumber() { return MakeCardinality(new EvenNumberCardinality); } ... EXPECT_CALL(foo, Bar(3)) .Times(EvenNumber()); ``` ### Writing New Actions {#QuickNewActions} If the built-in actions don't work for you, you can easily define your own one. All you need is a call operator with a signature compatible with the mocked function. So you can use a lambda: ```cpp MockFunction mock; EXPECT_CALL(mock, Call).WillOnce([](const int input) { return input * 7; }); EXPECT_EQ(mock.AsStdFunction()(2), 14); ``` Or a struct with a call operator (even a templated one): ```cpp struct MultiplyBy { template T operator()(T arg) { return arg * multiplier; } int multiplier; }; // Then use: // EXPECT_CALL(...).WillOnce(MultiplyBy{7}); ``` It's also fine for the callable to take no arguments, ignoring the arguments supplied to the mock function: ```cpp MockFunction mock; EXPECT_CALL(mock, Call).WillOnce([] { return 17; }); EXPECT_EQ(mock.AsStdFunction()(0), 17); ``` When used with `WillOnce`, the callable can assume it will be called at most once and is allowed to be a move-only type: ```cpp // An action that contains move-only types and has an &&-qualified operator, // demanding in the type system that it be called at most once. This can be // used with WillOnce, but the compiler will reject it if handed to // WillRepeatedly. struct MoveOnlyAction { std::unique_ptr move_only_state; std::unique_ptr operator()() && { return std::move(move_only_state); } }; MockFunction()> mock; EXPECT_CALL(mock, Call).WillOnce(MoveOnlyAction{std::make_unique(17)}); EXPECT_THAT(mock.AsStdFunction()(), Pointee(Eq(17))); ``` More generally, to use with a mock function whose signature is `R(Args...)` the object can be anything convertible to `OnceAction` or `Action. The difference between the two is that `OnceAction` has weaker requirements (`Action` requires a copy-constructible input that can be called repeatedly whereas `OnceAction` requires only move-constructible and supports `&&`-qualified call operators), but can be used only with `WillOnce`. `OnceAction` is typically relevant only when supporting move-only types or actions that want a type-system guarantee that they will be called at most once. Typically the `OnceAction` and `Action` templates need not be referenced directly in your actions: a struct or class with a call operator is sufficient, as in the examples above. But fancier polymorphic actions that need to know the specific return type of the mock function can define templated conversion operators to make that possible. See `gmock-actions.h` for examples. #### Legacy macro-based Actions Before C++11, the functor-based actions were not supported; the old way of writing actions was through a set of `ACTION*` macros. We suggest to avoid them in new code; they hide a lot of logic behind the macro, potentially leading to harder-to-understand compiler errors. Nevertheless, we cover them here for completeness. By writing ```cpp ACTION(name) { statements; } ``` in a namespace scope (i.e. not inside a class or function), you will define an action with the given name that executes the statements. The value returned by `statements` will be used as the return value of the action. Inside the statements, you can refer to the K-th (0-based) argument of the mock function as `argK`. For example: ```cpp ACTION(IncrementArg1) { return ++(*arg1); } ``` allows you to write ```cpp ... WillOnce(IncrementArg1()); ``` Note that you don't need to specify the types of the mock function arguments. Rest assured that your code is type-safe though: you'll get a compiler error if `*arg1` doesn't support the `++` operator, or if the type of `++(*arg1)` isn't compatible with the mock function's return type. Another example: ```cpp ACTION(Foo) { (*arg2)(5); Blah(); *arg1 = 0; return arg0; } ``` defines an action `Foo()` that invokes argument #2 (a function pointer) with 5, calls function `Blah()`, sets the value pointed to by argument #1 to 0, and returns argument #0. For more convenience and flexibility, you can also use the following pre-defined symbols in the body of `ACTION`: `argK_type` | The type of the K-th (0-based) argument of the mock function :-------------- | :----------------------------------------------------------- `args` | All arguments of the mock function as a tuple `args_type` | The type of all arguments of the mock function as a tuple `return_type` | The return type of the mock function `function_type` | The type of the mock function For example, when using an `ACTION` as a stub action for mock function: ```cpp int DoSomething(bool flag, int* ptr); ``` we have: Pre-defined Symbol | Is Bound To ------------------ | --------------------------------- `arg0` | the value of `flag` `arg0_type` | the type `bool` `arg1` | the value of `ptr` `arg1_type` | the type `int*` `args` | the tuple `(flag, ptr)` `args_type` | the type `std::tuple` `return_type` | the type `int` `function_type` | the type `int(bool, int*)` #### Legacy macro-based parameterized Actions Sometimes you'll want to parameterize an action you define. For that we have another macro ```cpp ACTION_P(name, param) { statements; } ``` For example, ```cpp ACTION_P(Add, n) { return arg0 + n; } ``` will allow you to write ```cpp // Returns argument #0 + 5. ... WillOnce(Add(5)); ``` For convenience, we use the term *arguments* for the values used to invoke the mock function, and the term *parameters* for the values used to instantiate an action. Note that you don't need to provide the type of the parameter either. Suppose the parameter is named `param`, you can also use the gMock-defined symbol `param_type` to refer to the type of the parameter as inferred by the compiler. For example, in the body of `ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. gMock also provides `ACTION_P2`, `ACTION_P3`, and etc to support multi-parameter actions. For example, ```cpp ACTION_P2(ReturnDistanceTo, x, y) { double dx = arg0 - x; double dy = arg1 - y; return sqrt(dx*dx + dy*dy); } ``` lets you write ```cpp ... WillOnce(ReturnDistanceTo(5.0, 26.5)); ``` You can view `ACTION` as a degenerated parameterized action where the number of parameters is 0. You can also easily define actions overloaded on the number of parameters: ```cpp ACTION_P(Plus, a) { ... } ACTION_P2(Plus, a, b) { ... } ``` ### Restricting the Type of an Argument or Parameter in an ACTION For maximum brevity and reusability, the `ACTION*` macros don't ask you to provide the types of the mock function arguments and the action parameters. Instead, we let the compiler infer the types for us. Sometimes, however, we may want to be more explicit about the types. There are several tricks to do that. For example: ```cpp ACTION(Foo) { // Makes sure arg0 can be converted to int. int n = arg0; ... use n instead of arg0 here ... } ACTION_P(Bar, param) { // Makes sure the type of arg1 is const char*. ::testing::StaticAssertTypeEq(); // Makes sure param can be converted to bool. bool flag = param; } ``` where `StaticAssertTypeEq` is a compile-time assertion in googletest that verifies two types are the same. ### Writing New Action Templates Quickly Sometimes you want to give an action explicit template parameters that cannot be inferred from its value parameters. `ACTION_TEMPLATE()` supports that and can be viewed as an extension to `ACTION()` and `ACTION_P*()`. The syntax: ```cpp ACTION_TEMPLATE(ActionName, HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } ``` defines an action template that takes *m* explicit template parameters and *n* value parameters, where *m* is in [1, 10] and *n* is in [0, 10]. `name_i` is the name of the *i*-th template parameter, and `kind_i` specifies whether it's a `typename`, an integral constant, or a template. `p_i` is the name of the *i*-th value parameter. Example: ```cpp // DuplicateArg(output) converts the k-th argument of the mock // function to type T and copies it to *output. ACTION_TEMPLATE(DuplicateArg, // Note the comma between int and k: HAS_2_TEMPLATE_PARAMS(int, k, typename, T), AND_1_VALUE_PARAMS(output)) { *output = T(std::get(args)); } ``` To create an instance of an action template, write: ```cpp ActionName(v1, ..., v_n) ``` where the `t`s are the template arguments and the `v`s are the value arguments. The value argument types are inferred by the compiler. For example: ```cpp using ::testing::_; ... int n; EXPECT_CALL(mock, Foo).WillOnce(DuplicateArg<1, unsigned char>(&n)); ``` If you want to explicitly specify the value argument types, you can provide additional template arguments: ```cpp ActionName(v1, ..., v_n) ``` where `u_i` is the desired type of `v_i`. `ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the number of value parameters, but not on the number of template parameters. Without the restriction, the meaning of the following is unclear: ```cpp OverloadedAction(x); ``` Are we using a single-template-parameter action where `bool` refers to the type of `x`, or a two-template-parameter action where the compiler is asked to infer the type of `x`? ### Using the ACTION Object's Type If you are writing a function that returns an `ACTION` object, you'll need to know its type. The type depends on the macro used to define the action and the parameter types. The rule is relatively simple: | Given Definition | Expression | Has Type | | ----------------------------- | ------------------- | --------------------- | | `ACTION(Foo)` | `Foo()` | `FooAction` | | `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | | `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | | `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `BarActionP` | | `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | | `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `BazActionP2` | | ... | ... | ... | Note that we have to pick different suffixes (`Action`, `ActionP`, `ActionP2`, and etc) for actions with different numbers of value parameters, or the action definitions cannot be overloaded on the number of them. ### Writing New Monomorphic Actions {#NewMonoActions} While the `ACTION*` macros are very convenient, sometimes they are inappropriate. For example, despite the tricks shown in the previous recipes, they don't let you directly specify the types of the mock function arguments and the action parameters, which in general leads to unoptimized compiler error messages that can baffle unfamiliar users. They also don't allow overloading actions based on parameter types without jumping through some hoops. An alternative to the `ACTION*` macros is to implement `::testing::ActionInterface`, where `F` is the type of the mock function in which the action will be used. For example: ```cpp template class ActionInterface { public: virtual ~ActionInterface(); // Performs the action. Result is the return type of function type // F, and ArgumentTuple is the tuple of arguments of F. // // For example, if F is int(bool, const string&), then Result would // be int, and ArgumentTuple would be std::tuple. virtual Result Perform(const ArgumentTuple& args) = 0; }; ``` ```cpp using ::testing::_; using ::testing::Action; using ::testing::ActionInterface; using ::testing::MakeAction; typedef int IncrementMethod(int*); class IncrementArgumentAction : public ActionInterface { public: int Perform(const std::tuple& args) override { int* p = std::get<0>(args); // Grabs the first argument. return *p++; } }; Action IncrementArgument() { return MakeAction(new IncrementArgumentAction); } ... EXPECT_CALL(foo, Baz(_)) .WillOnce(IncrementArgument()); int n = 5; foo.Baz(&n); // Should return 5 and change n to 6. ``` ### Writing New Polymorphic Actions {#NewPolyActions} The previous recipe showed you how to define your own action. This is all good, except that you need to know the type of the function in which the action will be used. Sometimes that can be a problem. For example, if you want to use the action in functions with *different* types (e.g. like `Return()` and `SetArgPointee()`). If an action can be used in several types of mock functions, we say it's *polymorphic*. The `MakePolymorphicAction()` function template makes it easy to define such an action: ```cpp namespace testing { template PolymorphicAction MakePolymorphicAction(const Impl& impl); } // namespace testing ``` As an example, let's define an action that returns the second argument in the mock function's argument list. The first step is to define an implementation class: ```cpp class ReturnSecondArgumentAction { public: template Result Perform(const ArgumentTuple& args) const { // To get the i-th (0-based) argument, use std::get(args). return std::get<1>(args); } }; ``` This implementation class does *not* need to inherit from any particular class. What matters is that it must have a `Perform()` method template. This method template takes the mock function's arguments as a tuple in a **single** argument, and returns the result of the action. It can be either `const` or not, but must be invocable with exactly one template argument, which is the result type. In other words, you must be able to call `Perform(args)` where `R` is the mock function's return type and `args` is its arguments in a tuple. Next, we use `MakePolymorphicAction()` to turn an instance of the implementation class into the polymorphic action we need. It will be convenient to have a wrapper for this: ```cpp using ::testing::MakePolymorphicAction; using ::testing::PolymorphicAction; PolymorphicAction ReturnSecondArgument() { return MakePolymorphicAction(ReturnSecondArgumentAction()); } ``` Now, you can use this polymorphic action the same way you use the built-in ones: ```cpp using ::testing::_; class MockFoo : public Foo { public: MOCK_METHOD(int, DoThis, (bool flag, int n), (override)); MOCK_METHOD(string, DoThat, (int x, const char* str1, const char* str2), (override)); }; ... MockFoo foo; EXPECT_CALL(foo, DoThis).WillOnce(ReturnSecondArgument()); EXPECT_CALL(foo, DoThat).WillOnce(ReturnSecondArgument()); ... foo.DoThis(true, 5); // Will return 5. foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". ``` ### Teaching gMock How to Print Your Values When an uninteresting or unexpected call occurs, gMock prints the argument values and the stack trace to help you debug. Assertion macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in question when the assertion fails. gMock and googletest do this using googletest's user-extensible value printer. This printer knows how to print built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hopes that you the user can figure it out. [The GoogleTest advanced guide](advanced.md#teaching-googletest-how-to-print-your-values) explains how to extend the printer to do a better job at printing your particular type than to dump the bytes. ## Useful Mocks Created Using gMock ### Mock std::function {#MockFunction} `std::function` is a general function type introduced in C++11. It is a preferred way of passing callbacks to new interfaces. Functions are copyable, and are not usually passed around by pointer, which makes them tricky to mock. But fear not - `MockFunction` can help you with that. `MockFunction` has a mock method `Call()` with the signature: ```cpp R Call(T1, ..., Tn); ``` It also has a `AsStdFunction()` method, which creates a `std::function` proxy forwarding to Call: ```cpp std::function AsStdFunction(); ``` To use `MockFunction`, first create `MockFunction` object and set up expectations on its `Call` method. Then pass proxy obtained from `AsStdFunction()` to the code you are testing. For example: ```cpp TEST(FooTest, RunsCallbackWithBarArgument) { // 1. Create a mock object. MockFunction mock_function; // 2. Set expectations on Call() method. EXPECT_CALL(mock_function, Call("bar")).WillOnce(Return(1)); // 3. Exercise code that uses std::function. Foo(mock_function.AsStdFunction()); // Foo's signature can be either of: // void Foo(const std::function& fun); // void Foo(std::function fun); // 4. All expectations will be verified when mock_function // goes out of scope and is destroyed. } ``` Remember that function objects created with `AsStdFunction()` are just forwarders. If you create multiple of them, they will share the same set of expectations. Although `std::function` supports unlimited number of arguments, `MockFunction` implementation is limited to ten. If you ever hit that limit... well, your callback has bigger problems than being mockable. :-) gperftools-gperftools-2.18/vendor/googletest/docs/gmock_faq.md000066400000000000000000000352041513545575200247040ustar00rootroot00000000000000# Legacy gMock FAQ ### When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? In order for a method to be mocked, it must be *virtual*, unless you use the [high-perf dependency injection technique](gmock_cook_book.md#MockingNonVirtualMethods). ### Can I mock a variadic function? You cannot mock a variadic function (i.e. a function taking ellipsis (`...`) arguments) directly in gMock. The problem is that in general, there is *no way* for a mock object to know how many arguments are passed to the variadic method, and what the arguments' types are. Only the *author of the base class* knows the protocol, and we cannot look into his or her head. Therefore, to mock such a function, the *user* must teach the mock object how to figure out the number of arguments and their types. One way to do it is to provide overloaded versions of the function. Ellipsis arguments are inherited from C and not really a C++ feature. They are unsafe to use and don't work with arguments that have constructors or destructors. Therefore we recommend to avoid them in C++ as much as possible. ### MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? If you compile this using Microsoft Visual C++ 2005 SP1: ```cpp class Foo { ... virtual void Bar(const int i) = 0; }; class MockFoo : public Foo { ... MOCK_METHOD(void, Bar, (const int i), (override)); }; ``` You may get the following warning: ```shell warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier ``` This is a MSVC bug. The same code compiles fine with gcc, for example. If you use Visual C++ 2008 SP1, you would get the warning: ```shell warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers ``` In C++, if you *declare* a function with a `const` parameter, the `const` modifier is ignored. Therefore, the `Foo` base class above is equivalent to: ```cpp class Foo { ... virtual void Bar(int i) = 0; // int or const int? Makes no difference. }; ``` In fact, you can *declare* `Bar()` with an `int` parameter, and define it with a `const int` parameter. The compiler will still match them up. Since making a parameter `const` is meaningless in the method declaration, we recommend to remove it in both `Foo` and `MockFoo`. That should workaround the VC bug. Note that we are talking about the *top-level* `const` modifier here. If the function parameter is passed by pointer or reference, declaring the pointee or referee as `const` is still meaningful. For example, the following two declarations are *not* equivalent: ```cpp void Bar(int* p); // Neither p nor *p is const. void Bar(const int* p); // p is not const, but *p is. ``` ### I can't figure out why gMock thinks my expectations are not satisfied. What should I do? You might want to run your test with `--gmock_verbose=info`. This flag lets gMock print a trace of every mock function call it receives. By studying the trace, you'll gain insights on why the expectations you set are not met. If you see the message "The mock function has no default action set, and its return type has no default value set.", then try [adding a default action](gmock_cheat_sheet.md#OnCall). Due to a known issue, unexpected calls on mocks without default actions don't print out a detailed comparison between the actual arguments and the expected arguments. ### My program crashed and `ScopedMockLog` spit out tons of messages. Is it a gMock bug? gMock and `ScopedMockLog` are likely doing the right thing here. When a test crashes, the failure signal handler will try to log a lot of information (the stack trace, and the address map, for example). The messages are compounded if you have many threads with depth stacks. When `ScopedMockLog` intercepts these messages and finds that they don't match any expectations, it prints an error for each of them. You can learn to ignore the errors, or you can rewrite your expectations to make your test more robust, for example, by adding something like: ```cpp using ::testing::AnyNumber; using ::testing::Not; ... // Ignores any log not done by us. EXPECT_CALL(log, Log(_, Not(EndsWith("/my_file.cc")), _)) .Times(AnyNumber()); ``` ### How can I assert that a function is NEVER called? ```cpp using ::testing::_; ... EXPECT_CALL(foo, Bar(_)) .Times(0); ``` ### I have a failed test where gMock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? When gMock detects a failure, it prints relevant information (the mock function arguments, the state of relevant expectations, and etc) to help the user debug. If another failure is detected, gMock will do the same, including printing the state of relevant expectations. Sometimes an expectation's state didn't change between two failures, and you'll see the same description of the state twice. They are however *not* redundant, as they refer to *different points in time*. The fact they are the same *is* interesting information. ### I get a heapcheck failure when using a mock object, but using a real object is fine. What can be wrong? Does the class (hopefully a pure interface) you are mocking have a virtual destructor? Whenever you derive from a base class, make sure its destructor is virtual. Otherwise Bad Things will happen. Consider the following code: ```cpp class Base { public: // Not virtual, but should be. ~Base() { ... } ... }; class Derived : public Base { public: ... private: std::string value_; }; ... Base* p = new Derived; ... delete p; // Surprise! ~Base() will be called, but ~Derived() will not // - value_ is leaked. ``` By changing `~Base()` to virtual, `~Derived()` will be correctly called when `delete p` is executed, and the heap checker will be happy. ### The "newer expectations override older ones" rule makes writing expectations awkward. Why does gMock do that? When people complain about this, often they are referring to code like: ```cpp using ::testing::Return; ... // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. However, I have to write the expectations in the // reverse order. This sucks big time!!! EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); ``` The problem, is that they didn't pick the **best** way to express the test's intent. By default, expectations don't have to be matched in *any* particular order. If you want them to match in a certain order, you need to be explicit. This is gMock's (and jMock's) fundamental philosophy: it's easy to accidentally over-specify your tests, and we want to make it harder to do so. There are two better ways to write the test spec. You could either put the expectations in sequence: ```cpp using ::testing::Return; ... // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. Using a sequence, we can write the expectations // in their natural order. { InSequence s; EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); } ``` or you can put the sequence of actions in the same expectation: ```cpp using ::testing::Return; ... // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .WillOnce(Return(2)) .RetiresOnSaturation(); ``` Back to the original questions: why does gMock search the expectations (and `ON_CALL`s) from back to front? Because this allows a user to set up a mock's behavior for the common case early (e.g. in the mock's constructor or the test fixture's set-up phase) and customize it with more specific rules later. If gMock searches from front to back, this very useful pattern won't be possible. ### gMock prints a warning when a function without EXPECT_CALL is called, even if I have set its behavior using ON_CALL. Would it be reasonable not to show the warning in this case? When choosing between being neat and being safe, we lean toward the latter. So the answer is that we think it's better to show the warning. Often people write `ON_CALL`s in the mock object's constructor or `SetUp()`, as the default behavior rarely changes from test to test. Then in the test body they set the expectations, which are often different for each test. Having an `ON_CALL` in the set-up part of a test doesn't mean that the calls are expected. If there's no `EXPECT_CALL` and the method is called, it's possibly an error. If we quietly let the call go through without notifying the user, bugs may creep in unnoticed. If, however, you are sure that the calls are OK, you can write ```cpp using ::testing::_; ... EXPECT_CALL(foo, Bar(_)) .WillRepeatedly(...); ``` instead of ```cpp using ::testing::_; ... ON_CALL(foo, Bar(_)) .WillByDefault(...); ``` This tells gMock that you do expect the calls and no warning should be printed. Also, you can control the verbosity by specifying `--gmock_verbose=error`. Other values are `info` and `warning`. If you find the output too noisy when debugging, just choose a less verbose level. ### How can I delete the mock function's argument in an action? If your mock function takes a pointer argument and you want to delete that argument, you can use testing::DeleteArg() to delete the N'th (zero-indexed) argument: ```cpp using ::testing::_; ... MOCK_METHOD(void, Bar, (X* x, const Y& y)); ... EXPECT_CALL(mock_foo_, Bar(_, _)) .WillOnce(testing::DeleteArg<0>())); ``` ### How can I perform an arbitrary action on a mock function's argument? If you find yourself needing to perform some action that's not supported by gMock directly, remember that you can define your own actions using [`MakeAction()`](#NewMonoActions) or [`MakePolymorphicAction()`](#NewPolyActions), or you can write a stub function and invoke it using [`Invoke()`](#FunctionsAsActions). ```cpp using ::testing::_; using ::testing::Invoke; ... MOCK_METHOD(void, Bar, (X* p)); ... EXPECT_CALL(mock_foo_, Bar(_)) .WillOnce(Invoke(MyAction(...))); ``` ### My code calls a static/global function. Can I mock it? You can, but you need to make some changes. In general, if you find yourself needing to mock a static function, it's a sign that your modules are too tightly coupled (and less flexible, less reusable, less testable, etc). You are probably better off defining a small interface and call the function through that interface, which then can be easily mocked. It's a bit of work initially, but usually pays for itself quickly. This Google Testing Blog [post](https://testing.googleblog.com/2008/06/defeat-static-cling.html) says it excellently. Check it out. ### My mock object needs to do complex stuff. It's a lot of pain to specify the actions. gMock sucks! I know it's not a question, but you get an answer for free any way. :-) With gMock, you can create mocks in C++ easily. And people might be tempted to use them everywhere. Sometimes they work great, and sometimes you may find them, well, a pain to use. So, what's wrong in the latter case? When you write a test without using mocks, you exercise the code and assert that it returns the correct value or that the system is in an expected state. This is sometimes called "state-based testing". Mocks are great for what some call "interaction-based" testing: instead of checking the system state at the very end, mock objects verify that they are invoked the right way and report an error as soon as it arises, giving you a handle on the precise context in which the error was triggered. This is often more effective and economical to do than state-based testing. If you are doing state-based testing and using a test double just to simulate the real object, you are probably better off using a fake. Using a mock in this case causes pain, as it's not a strong point for mocks to perform complex actions. If you experience this and think that mocks suck, you are just not using the right tool for your problem. Or, you might be trying to solve the wrong problem. :-) ### I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? By all means, NO! It's just an FYI. :-) What it means is that you have a mock function, you haven't set any expectations on it (by gMock's rule this means that you are not interested in calls to this function and therefore it can be called any number of times), and it is called. That's OK - you didn't say it's not OK to call the function! What if you actually meant to disallow this function to be called, but forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While one can argue that it's the user's fault, gMock tries to be nice and prints you a note. So, when you see the message and believe that there shouldn't be any uninteresting calls, you should investigate what's going on. To make your life easier, gMock dumps the stack trace when an uninteresting call is encountered. From that you can figure out which mock function it is, and how it is called. ### I want to define a custom action. Should I use Invoke() or implement the ActionInterface interface? Either way is fine - you want to choose the one that's more convenient for your circumstance. Usually, if your action is for a particular function type, defining it using `Invoke()` should be easier; if your action can be used in functions of different types (e.g. if you are defining `Return(*value*)`), `MakePolymorphicAction()` is easiest. Sometimes you want precise control on what types of functions the action can be used in, and implementing `ActionInterface` is the way to go here. See the implementation of `Return()` in `gmock-actions.h` for an example. ### I use SetArgPointee() in WillOnce(), but gcc complains about "conflicting return type specified". What does it mean? You got this error as gMock has no idea what value it should return when the mock method is called. `SetArgPointee()` says what the side effect is, but doesn't say what the return value should be. You need `DoAll()` to chain a `SetArgPointee()` with a `Return()` that provides a value appropriate to the API being mocked. See this [recipe](gmock_cook_book.md#mocking-side-effects) for more details and an example. ### I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? We've noticed that when the `/clr` compiler flag is used, Visual C++ uses 5~6 times as much memory when compiling a mock class. We suggest to avoid `/clr` when compiling native C++ mocks. gperftools-gperftools-2.18/vendor/googletest/docs/gmock_for_dummies.md000066400000000000000000000710531513545575200264500ustar00rootroot00000000000000# gMock for Dummies ## What Is gMock? When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). It is easy to confuse the term *fake objects* with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. * **Mocks** are objects pre-programmed with *expectations*, which form a specification of the calls they are expected to receive. If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the *interaction* between itself and code that uses it. The difference between fakes and mocks shall become much clearer once you start to use mocks. **gMock** is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what jMock/EasyMock does to Java (well, more or less). When using gMock, 1. first, you use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; 2. next, you create some mock objects and specify its expectations and behavior using an intuitive syntax; 3. then you exercise code that uses the mock objects. gMock will catch any violation to the expectations as soon as it arises. ## Why gMock? While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is *hard*: * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. * The knowledge you gained from using one mock doesn't transfer to the next one. In contrast, Java and Python programmers have some fine mock frameworks (jMock, EasyMock, etc), which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. gMock was built to help C++ programmers. It was inspired by jMock and EasyMock, but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). * Your tests are brittle as some resources they use are unreliable (e.g. the network). * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, but it's awkward at best. * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. We encourage you to use gMock as * a *design* tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! * a *testing* tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. ## Getting Started gMock is bundled with googletest. ## A Case for Mock Turtles Let's look at an example. Suppose you are developing a graphics program that relies on a [LOGO](https://en.wikipedia.org/wiki/Logo_programming_language)-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) and know the right thing to do: instead of having your application talk to the system API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: ```cpp class Turtle { ... virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; virtual void Turn(int degrees) = 0; virtual void GoTo(int x, int y) = 0; virtual int GetX() const = 0; virtual int GetY() const = 0; }; ``` (Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run *much, much faster*. ## Writing the Mock Class If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - gMock turns this task into a fun game! (Well, almost.) ### How to Define It Using the `Turtle` interface as example, here are the simple steps you need to follow: * Derive a class `MockTurtle` from `Turtle`. * Take a *virtual* function of `Turtle` (while it's possible to [mock non-virtual methods using templates](gmock_cook_book.md#MockingNonVirtualMethods), it's much more involved). * In the `public:` section of the child class, write `MOCK_METHOD();` * Now comes the fun part: you take the function signature, cut-and-paste it into the macro, and add two commas - one between the return type and the name, another between the name and the argument list. * If you're mocking a const method, add a 4th parameter containing `(const)` (the parentheses are required). * Since you're overriding a virtual method, we suggest adding the `override` keyword. For const methods the 4th parameter becomes `(const, override)`, for non-const methods just `(override)`. This isn't mandatory. * Repeat until all virtual functions you want to mock are done. (It goes without saying that *all* pure virtual methods in your abstract class must be either mocked or overridden.) After the process, you should have something like: ```cpp #include // Brings in gMock. class MockTurtle : public Turtle { public: ... MOCK_METHOD(void, PenUp, (), (override)); MOCK_METHOD(void, PenDown, (), (override)); MOCK_METHOD(void, Forward, (int distance), (override)); MOCK_METHOD(void, Turn, (int degrees), (override)); MOCK_METHOD(void, GoTo, (int x, int y), (override)); MOCK_METHOD(int, GetX, (), (const, override)); MOCK_METHOD(int, GetY, (), (const, override)); }; ``` You don't need to define these mock methods somewhere else - the `MOCK_METHOD` macro will generate the definitions for you. It's that simple! ### Where to Put It When you define a mock class, you need to decide where to put its definition. Some people put it in a `_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) Generally, you should not mock classes you don't own. If you must mock such a class owned by others, define the mock class in `Foo`'s Bazel package (usually the same directory or a `testing` sub-directory), and put it in a `.h` and a `cc_library` with `testonly=True`. Then everyone can reference them from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. ## Using Mocks in Tests Once you have a mock class, using it is easy. The typical work flow is: 1. Import the gMock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file). Remember that namespaces are a good idea. 2. Create some mock objects. 3. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). 4. Exercise some code that uses the mocks; optionally, check the result using googletest assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. 5. When a mock is destructed, gMock will automatically check whether all expectations on it have been satisfied. Here's an example: ```cpp #include "path/to/mock-turtle.h" #include #include using ::testing::AtLeast; // #1 TEST(PainterTest, CanDrawSomething) { MockTurtle turtle; // #2 EXPECT_CALL(turtle, PenDown()) // #3 .Times(AtLeast(1)); Painter painter(&turtle); // #4 EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); // #5 } ``` As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: ```text path/to/my_test.cc:119: Failure Actual function call count doesn't match this expectation: Actually: never called; Expected: called at least once. Stack trace: ... ``` **Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number to jump right to the failed expectation. **Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to turn on the heap checker in your tests when you allocate mocks on the heap. You get that automatically if you use the `gtest_main` library already. ###### Expectation Ordering **Important note:** gMock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. Do not alternate between calls to `EXPECT_CALL()` and calls to the mock functions, and do not set any expectations on a mock after passing the mock to an API. This means `EXPECT_CALL()` should be read as expecting that a call will occur *in the future*, not that a call has occurred. Why does gMock work like that? Well, specifying the expectation beforehand allows gMock to report a violation as soon as it rises, when the context (stack trace, etc) is still available. This makes debugging much easier. Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using gMock. However, as we shall reveal soon, gMock allows you to do *so much more* with the mocks. ## Setting Expectations The key to using a mock object successfully is to set the *right expectations* on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. gMock provides the necessary means for you to do it "just right." ### General Syntax In gMock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: ```cpp EXPECT_CALL(mock_object, method(matchers)) .Times(cardinality) .WillOnce(action) .WillRepeatedly(action); ``` The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) If the method is not overloaded, the macro can also be called without matchers: ```cpp EXPECT_CALL(mock_object, non-overloaded-method) .Times(cardinality) .WillOnce(action) .WillRepeatedly(action); ``` This syntax allows the test writer to specify "called with any arguments" without explicitly specifying the number or types of arguments. To avoid unintended ambiguity, this syntax may only be used for methods that are not overloaded. Either form of the macro can be followed by some optional *clauses* that provide more information about the expectation. We'll discuss how each clause works in the coming sections. This syntax is designed to make an expectation read like English. For example, you can probably guess that ```cpp using ::testing::Return; ... EXPECT_CALL(turtle, GetX()) .Times(5) .WillOnce(Return(100)) .WillOnce(Return(150)) .WillRepeatedly(Return(200)); ``` says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). {: .callout .note} **Note:** Why do we use a macro to do this? Well it serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows gMock to include the source file location of a failed expectation in messages, making debugging easier. ### Matchers: What Arguments Do We Expect? When a mock function takes arguments, we may specify what arguments we are expecting, for example: ```cpp // Expects the turtle to move forward by 100 units. EXPECT_CALL(turtle, Forward(100)); ``` Oftentimes you do not want to be too specific. Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary—no more, no less. If you aren't interested in the value of an argument, write `_` as the argument, which means "anything goes": ```cpp using ::testing::_; ... // Expects that the turtle jumps to somewhere on the x=50 line. EXPECT_CALL(turtle, GoTo(50, _)); ``` `_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. `_` is a convenient way of saying "any value". In the above examples, `100` and `50` are also matchers; implicitly, they are the same as `Eq(100)` and `Eq(50)`, which specify that the argument must be equal (using `operator==`) to the matcher argument. There are many [built-in matchers](reference/matchers.md) for common types (as well as [custom matchers](gmock_cook_book.md#NewMatchers)); for example: ```cpp using ::testing::Ge; ... // Expects the turtle moves forward by at least 100. EXPECT_CALL(turtle, Forward(Ge(100))); ``` If you don't care about *any* arguments, rather than specify `_` for each of them you may instead omit the parameter list: ```cpp // Expects the turtle to move forward. EXPECT_CALL(turtle, Forward); // Expects the turtle to jump somewhere. EXPECT_CALL(turtle, GoTo); ``` This works for all non-overloaded methods; if a method is overloaded, you need to help gMock resolve which overload is expected by specifying the number of arguments and possibly also the [types of the arguments](gmock_cook_book.md#SelectOverload). ### Cardinalities: How Many Times Will It Be Called? The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells *how many times* the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and gMock will report a googletest failure whenever the function is (wrongfully) called. We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see [here](gmock_cheat_sheet.md#CardinalityList). The `Times()` clause can be omitted. **If you omit `Times()`, gMock will infer the cardinality for you.** The rules are easy to remember: * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. * If there are *n* `WillOnce()`'s but **no** `WillRepeatedly()`, where *n* >= 1, the cardinality is `Times(n)`. * If there are *n* `WillOnce()`'s and **one** `WillRepeatedly()`, where *n* >= 0, the cardinality is `Times(AtLeast(n))`. **Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? ### Actions: What Should It Do? Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in gMock. First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). In addition, in C++ 11 and above, a mock function whose return type is default-constructible (i.e. has a default constructor) has a default action of returning a default-constructed value. If you don't say anything, this behavior will be used. Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, ```cpp using ::testing::Return; ... EXPECT_CALL(turtle, GetX()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillOnce(Return(300)); ``` says that `turtle.GetX()` will be called *exactly three times* (gMock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. ```cpp using ::testing::Return; ... EXPECT_CALL(turtle, GetY()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillRepeatedly(Return(300)); ``` says that `turtle.GetY()` will be called *at least twice* (gMock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 and 200 respectively the first two times, and 300 from the third time on. Of course, if you explicitly write a `Times()`, gMock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, gMock will do the *default* action for the function every time (unless, of course, you have a `WillRepeatedly()`.). What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(`*`variable`*`)`, or invoke a pre-defined function, among [others](gmock_cook_book.md#using-actions). **Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: ```cpp using ::testing::Return; ... int n = 100; EXPECT_CALL(turtle, GetX()) .Times(4) .WillRepeatedly(Return(n++)); ``` Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [cook book](gmock_cook_book.md). Time for another quiz! What do you think the following means? ```cpp using ::testing::Return; ... EXPECT_CALL(turtle, GetY()) .Times(4) .WillOnce(Return(100)); ``` Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. ### Using Multiple Expectations {#MultiExpectations} So far we've only shown examples where you have a single expectation. More realistically, you'll specify expectations on multiple mock methods which may be from multiple mock objects. By default, when a mock method is invoked, gMock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: ```cpp using ::testing::_; ... EXPECT_CALL(turtle, Forward(_)); // #1 EXPECT_CALL(turtle, Forward(10)) // #2 .Times(2); ``` If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. {: .callout .note} **Note:** Why does gMock search for a match in the *reverse* order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. {: .callout .tip} **Tip:** It is very common to start with a catch-all expectation for a method and `Times(AnyNumber())` (omitting arguments, or with `_` for all arguments, if overloaded). This makes any calls to the method expected. This is not necessary for methods that are not mentioned at all (these are "uninteresting"), but is useful for methods that have some expectations, but for which other calls are ok. See [Understanding Uninteresting vs Unexpected Calls](gmock_cook_book.md#uninteresting-vs-unexpected). ### Ordered vs Unordered Calls {#OrderedCalls} By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. Sometimes, you may want all the expected calls to occur in a strict order. To say this in gMock is easy: ```cpp using ::testing::InSequence; ... TEST(FooTest, DrawsLineSegment) { ... { InSequence seq; EXPECT_CALL(turtle, PenDown()); EXPECT_CALL(turtle, Forward(100)); EXPECT_CALL(turtle, PenUp()); } Foo(); } ``` By creating an object of type `InSequence`, all expectations in its scope are put into a *sequence* and have to occur *sequentially*. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. (What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! The details can be found [here](gmock_cook_book.md#OrderedCalls).) ### All Expectations Are Sticky (Unless Said Otherwise) {#StickyExpectations} Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin *exactly twice* (you want to ignore any other instructions it receives)? After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): ```cpp using ::testing::_; using ::testing::AnyNumber; ... EXPECT_CALL(turtle, GoTo(_, _)) // #1 .Times(AnyNumber()); EXPECT_CALL(turtle, GoTo(0, 0)) // #2 .Times(2); ``` Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, gMock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, gMock will report an error immediately. This is basically what we've told you in the [Using Multiple Expectations](#MultiExpectations) section above. This example shows that **expectations in gMock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). Simple? Let's see if you've really understood it: what does the following code say? ```cpp using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)); } ``` If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound violated" error - this piece of code is not very useful! One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are *not* sticky. In other words, they should *retire* as soon as they are saturated: ```cpp using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } ``` And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: ```cpp using ::testing::InSequence; using ::testing::Return; ... { InSequence s; for (int i = 1; i <= n; i++) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } } ``` By the way, the other situation where an expectation may *not* be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). ### Uninteresting Calls A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. In gMock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. This is called "naggy" behavior; to change, see [The Nice, the Strict, and the Naggy](gmock_cook_book.md#NiceStrictNaggy). gperftools-gperftools-2.18/vendor/googletest/docs/index.md000066400000000000000000000020121513545575200240530ustar00rootroot00000000000000# GoogleTest User's Guide ## Welcome to GoogleTest! GoogleTest is Google's C++ testing and mocking framework. This user's guide has the following contents: * [GoogleTest Primer](primer.md) - Teaches you how to write simple tests using GoogleTest. Read this first if you are new to GoogleTest. * [GoogleTest Advanced](advanced.md) - Read this when you've finished the Primer and want to utilize GoogleTest to its full potential. * [GoogleTest Samples](samples.md) - Describes some GoogleTest samples. * [GoogleTest FAQ](faq.md) - Have a question? Want some tips? Check here first. * [Mocking for Dummies](gmock_for_dummies.md) - Teaches you how to create mock objects and use them in tests. * [Mocking Cookbook](gmock_cook_book.md) - Includes tips and approaches to common mocking use cases. * [Mocking Cheat Sheet](gmock_cheat_sheet.md) - A handy reference for matchers, actions, invariants, and more. * [Mocking FAQ](gmock_faq.md) - Contains answers to some mocking-specific questions. gperftools-gperftools-2.18/vendor/googletest/docs/pkgconfig.md000066400000000000000000000115651513545575200247300ustar00rootroot00000000000000## Using GoogleTest from various build systems GoogleTest comes with pkg-config files that can be used to determine all necessary flags for compiling and linking to GoogleTest (and GoogleMock). Pkg-config is a standardised plain-text format containing * the includedir (-I) path * necessary macro (-D) definitions * further required flags (-pthread) * the library (-L) path * the library (-l) to link to All current build systems support pkg-config in one way or another. For all examples here we assume you want to compile the sample `samples/sample3_unittest.cc`. ### CMake Using `pkg-config` in CMake is fairly easy: ```cmake find_package(PkgConfig) pkg_search_module(GTEST REQUIRED gtest_main) add_executable(testapp) target_sources(testapp PRIVATE samples/sample3_unittest.cc) target_link_libraries(testapp PRIVATE ${GTEST_LDFLAGS}) target_compile_options(testapp PRIVATE ${GTEST_CFLAGS}) enable_testing() add_test(first_and_only_test testapp) ``` It is generally recommended that you use `target_compile_options` + `_CFLAGS` over `target_include_directories` + `_INCLUDE_DIRS` as the former includes not just -I flags (GoogleTest might require a macro indicating to internal headers that all libraries have been compiled with threading enabled. In addition, GoogleTest might also require `-pthread` in the compiling step, and as such splitting the pkg-config `Cflags` variable into include dirs and macros for `target_compile_definitions()` might still miss this). The same recommendation goes for using `_LDFLAGS` over the more commonplace `_LIBRARIES`, which happens to discard `-L` flags and `-pthread`. ### Help! pkg-config can't find GoogleTest! Let's say you have a `CMakeLists.txt` along the lines of the one in this tutorial and you try to run `cmake`. It is very possible that you get a failure along the lines of: ``` -- Checking for one of the modules 'gtest_main' CMake Error at /usr/share/cmake/Modules/FindPkgConfig.cmake:640 (message): None of the required 'gtest_main' found ``` These failures are common if you installed GoogleTest yourself and have not sourced it from a distro or other package manager. If so, you need to tell pkg-config where it can find the `.pc` files containing the information. Say you installed GoogleTest to `/usr/local`, then it might be that the `.pc` files are installed under `/usr/local/lib64/pkgconfig`. If you set ``` export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig ``` pkg-config will also try to look in `PKG_CONFIG_PATH` to find `gtest_main.pc`. ### Using pkg-config in a cross-compilation setting Pkg-config can be used in a cross-compilation setting too. To do this, let's assume the final prefix of the cross-compiled installation will be `/usr`, and your sysroot is `/home/MYUSER/sysroot`. Configure and install GTest using ``` mkdir build && cmake -DCMAKE_INSTALL_PREFIX=/usr .. ``` Install into the sysroot using `DESTDIR`: ``` make -j install DESTDIR=/home/MYUSER/sysroot ``` Before we continue, it is recommended to **always** define the following two variables for pkg-config in a cross-compilation setting: ``` export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=yes export PKG_CONFIG_ALLOW_SYSTEM_LIBS=yes ``` otherwise `pkg-config` will filter `-I` and `-L` flags against standard prefixes such as `/usr` (see https://bugs.freedesktop.org/show_bug.cgi?id=28264#c3 for reasons why this stripping needs to occur usually). If you look at the generated pkg-config file, it will look something like ``` libdir=/usr/lib64 includedir=/usr/include Name: gtest Description: GoogleTest (without main() function) Version: 1.11.0 URL: https://github.com/google/googletest Libs: -L${libdir} -lgtest -lpthread Cflags: -I${includedir} -DGTEST_HAS_PTHREAD=1 -lpthread ``` Notice that the sysroot is not included in `libdir` and `includedir`! If you try to run `pkg-config` with the correct `PKG_CONFIG_LIBDIR=/home/MYUSER/sysroot/usr/lib64/pkgconfig` against this `.pc` file, you will get ``` $ pkg-config --cflags gtest -DGTEST_HAS_PTHREAD=1 -lpthread -I/usr/include $ pkg-config --libs gtest -L/usr/lib64 -lgtest -lpthread ``` which is obviously wrong and points to the `CBUILD` and not `CHOST` root. In order to use this in a cross-compilation setting, we need to tell pkg-config to inject the actual sysroot into `-I` and `-L` variables. Let us now tell pkg-config about the actual sysroot ``` export PKG_CONFIG_DIR= export PKG_CONFIG_SYSROOT_DIR=/home/MYUSER/sysroot export PKG_CONFIG_LIBDIR=${PKG_CONFIG_SYSROOT_DIR}/usr/lib64/pkgconfig ``` and running `pkg-config` again we get ``` $ pkg-config --cflags gtest -DGTEST_HAS_PTHREAD=1 -lpthread -I/home/MYUSER/sysroot/usr/include $ pkg-config --libs gtest -L/home/MYUSER/sysroot/usr/lib64 -lgtest -lpthread ``` which contains the correct sysroot now. For a more comprehensive guide to also including `${CHOST}` in build system calls, see the excellent tutorial by Diego Elio Pettenò: gperftools-gperftools-2.18/vendor/googletest/docs/platforms.md000066400000000000000000000005271513545575200247640ustar00rootroot00000000000000# Supported Platforms GoogleTest follows Google's [Foundational C++ Support Policy](https://opensource.google/documentation/policies/cplusplus-support). See [this table](https://github.com/google/oss-policies-info/blob/main/foundational-cxx-support-matrix.md) for a list of currently supported versions compilers, platforms, and build tools. gperftools-gperftools-2.18/vendor/googletest/docs/primer.md000066400000000000000000000452351513545575200242600ustar00rootroot00000000000000# GoogleTest Primer ## Introduction: Why GoogleTest? *GoogleTest* helps you write better C++ tests. GoogleTest is a testing framework developed by the Testing Technology team with Google's specific requirements and constraints in mind. Whether you work on Linux, Windows, or a Mac, if you write C++ code, GoogleTest can help you. And it supports *any* kind of tests, not just unit tests. So what makes a good test, and how does GoogleTest fit in? We believe: 1. Tests should be *independent* and *repeatable*. It's a pain to debug a test that succeeds or fails as a result of other tests. GoogleTest isolates the tests by running each of them on a different object. When a test fails, GoogleTest allows you to run it in isolation for quick debugging. 2. Tests should be well *organized* and reflect the structure of the tested code. GoogleTest groups related tests into test suites that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base. 3. Tests should be *portable* and *reusable*. Google has a lot of code that is platform-neutral; its tests should also be platform-neutral. GoogleTest works on different OSes, with different compilers, with or without exceptions, so GoogleTest tests can work with a variety of configurations. 4. When tests fail, they should provide as much *information* about the problem as possible. GoogleTest doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle. 5. The testing framework should liberate test writers from housekeeping chores and let them focus on the test *content*. GoogleTest automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them. 6. Tests should be *fast*. With GoogleTest, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other. Since GoogleTest is based on the popular xUnit architecture, you'll feel right at home if you've used JUnit or PyUnit before. If not, it will take you about 10 minutes to learn the basics and get started. So let's go! ## Beware of the Nomenclature {: .callout .note} *Note:* There might be some confusion arising from different definitions of the terms *Test*, *Test Case* and *Test Suite*, so beware of misunderstanding these. Historically, GoogleTest started to use the term *Test Case* for grouping related tests, whereas current publications, including International Software Testing Qualifications Board ([ISTQB](https://www.istqb.org/)) materials and various textbooks on software quality, use the term *[Test Suite][istqb test suite]* for this. The related term *Test*, as it is used in GoogleTest, corresponds to the term *[Test Case][istqb test case]* of ISTQB and others. The term *Test* is commonly of broad enough sense, including ISTQB's definition of *Test Case*, so it's not much of a problem here. But the term *Test Case* as was used in Google Test is of contradictory sense and thus confusing. GoogleTest recently started replacing the term *Test Case* with *Test Suite*. The preferred API is *TestSuite*. The older TestCase API is being slowly deprecated and refactored away. So please be aware of the different definitions of the terms: Meaning | GoogleTest Term | [ISTQB](https://www.istqb.org/) Term :----------------------------------------------------------------------------------- | :---------------------- | :---------------------------------- Exercise a particular program path with specific input values and verify the results | [TEST()](#simple-tests) | [Test Case][istqb test case] [istqb test case]: https://glossary.istqb.org/en_US/term/test-case [istqb test suite]: https://glossary.istqb.org/en_US/term/test-suite ## Basic Concepts When using GoogleTest, you start by writing *assertions*, which are statements that check whether a condition is true. An assertion's result can be *success*, *nonfatal failure*, or *fatal failure*. If a fatal failure occurs, it aborts the current function; otherwise the program continues normally. *Tests* use assertions to verify the tested code's behavior. If a test crashes or has a failed assertion, then it *fails*; otherwise it *succeeds*. A *test suite* contains one or many tests. You should group your tests into test suites that reflect the structure of the tested code. When multiple tests in a test suite need to share common objects and subroutines, you can put them into a *test fixture* class. A *test program* can contain multiple test suites. We'll now explain how to write a test program, starting at the individual assertion level and building up to tests and test suites. ## Assertions GoogleTest assertions are macros that resemble function calls. You test a class or function by making assertions about its behavior. When an assertion fails, GoogleTest prints the assertion's source file and line number location, along with a failure message. You may also supply a custom failure message which will be appended to GoogleTest's message. The assertions come in pairs that test the same thing but have different effects on the current function. `ASSERT_*` versions generate fatal failures when they fail, and **abort the current function**. `EXPECT_*` versions generate nonfatal failures, which don't abort the current function. Usually `EXPECT_*` are preferred, as they allow more than one failure to be reported in a test. However, you should use `ASSERT_*` if it doesn't make sense to continue when the assertion in question fails. Since a failed `ASSERT_*` returns from the current function immediately, possibly skipping clean-up code that comes after it, it may cause a space leak. Depending on the nature of the leak, it may or may not be worth fixing - so keep this in mind if you get a heap checker error in addition to assertion errors. To provide a custom failure message, simply stream it into the macro using the `<<` operator or a sequence of such operators. See the following example, using the [`ASSERT_EQ` and `EXPECT_EQ`](reference/assertions.md#EXPECT_EQ) macros to verify value equality: ```c++ ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; } ``` Anything that can be streamed to an `ostream` can be streamed to an assertion macro--in particular, C strings and `string` objects. If a wide string (`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is streamed to an assertion, it will be translated to UTF-8 when printed. GoogleTest provides a collection of assertions for verifying the behavior of your code in various ways. You can check Boolean conditions, compare values based on relational operators, verify string values, floating-point values, and much more. There are even assertions that enable you to verify more complex states by providing custom predicates. For the complete list of assertions provided by GoogleTest, see the [Assertions Reference](reference/assertions.md). ## Simple Tests To create a test: 1. Use the `TEST()` macro to define and name a test function. These are ordinary C++ functions that don't return a value. 2. In this function, along with any valid C++ statements you want to include, use the various GoogleTest assertions to check values. 3. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds. ```c++ TEST(TestSuiteName, TestName) { ... test body ... } ``` `TEST()` arguments go from general to specific. The *first* argument is the name of the test suite, and the *second* argument is the test's name within the test suite. Both names must be valid C++ identifiers, and they should not contain any underscores (`_`). A test's *full name* consists of its containing test suite and its individual name. Tests from different test suites can have the same individual name. For example, let's take a simple integer function: ```c++ int Factorial(int n); // Returns the factorial of n ``` A test suite for this function might look like: ```c++ // Tests factorial of 0. TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(Factorial(0), 1); } // Tests factorial of positive numbers. TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(Factorial(1), 1); EXPECT_EQ(Factorial(2), 2); EXPECT_EQ(Factorial(3), 6); EXPECT_EQ(Factorial(8), 40320); } ``` GoogleTest groups the test results by test suites, so logically related tests should be in the same test suite; in other words, the first argument to their `TEST()` should be the same. In the above example, we have two tests, `HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test suite `FactorialTest`. When naming your test suites and tests, you should follow the same convention as for [naming functions and classes](https://google.github.io/styleguide/cppguide.html#Function_Names). **Availability**: Linux, Windows, Mac. ## Test Fixtures: Using the Same Data Configuration for Multiple Tests {#same-data-multiple-tests} If you find yourself writing two or more tests that operate on similar data, you can use a *test fixture*. This allows you to reuse the same configuration of objects for several different tests. To create a fixture: 1. Derive a class from `testing::Test` . Start its body with `protected:`, as we'll want to access fixture members from sub-classes. 2. Inside the class, declare any objects you plan to use. 3. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as **`Setup()`** with a small `u` - Use `override` in C++11 to make sure you spelled it correctly. 4. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read the [FAQ](faq.md#CtorVsSetUp). 5. If needed, define subroutines for your tests to share. When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to access objects and subroutines in the test fixture: ```c++ TEST_F(TestFixtureClassName, TestName) { ... test body ... } ``` Unlike `TEST()`, in `TEST_F()` the first argument must be the name of the test fixture class. (`_F` stands for "Fixture"). No test suite name is specified for this macro. Unfortunately, the C++ macro system does not allow us to create a single macro that can handle both types of tests. Using the wrong macro causes a compiler error. Also, you must first define a test fixture class before using it in a `TEST_F()`, or you'll get the compiler error "`virtual outside class declaration`". For each test defined with `TEST_F()`, GoogleTest will create a *fresh* test fixture at runtime, immediately initialize it via `SetUp()`, run the test, clean up by calling `TearDown()`, and then delete the test fixture. Note that different tests in the same test suite have different test fixture objects, and GoogleTest always deletes a test fixture before it creates the next one. GoogleTest does **not** reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests. As an example, let's write tests for a FIFO queue class named `Queue`, which has the following interface: ```c++ template // E is the element type. class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // Returns NULL if the queue is empty. size_t size() const; ... }; ``` First, define a fixture class. By convention, you should give it the name `FooTest` where `Foo` is the class being tested. ```c++ class QueueTest : public testing::Test { protected: QueueTest() { // q0_ remains empty q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // ~QueueTest() override = default; Queue q0_; Queue q1_; Queue q2_; }; ``` In this case, we don't need to define a destructor or a `TearDown()` method, because the implicit destructor generated by the compiler will perform all of the necessary cleanup. Now we'll write tests using `TEST_F()` and this fixture. ```c++ TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(q0_.size(), 0); } TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(n, nullptr); n = q1_.Dequeue(); ASSERT_NE(n, nullptr); EXPECT_EQ(*n, 1); EXPECT_EQ(q1_.size(), 0); delete n; n = q2_.Dequeue(); ASSERT_NE(n, nullptr); EXPECT_EQ(*n, 2); EXPECT_EQ(q2_.size(), 1); delete n; } ``` The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is to use `EXPECT_*` when you want the test to continue to reveal more errors after the assertion failure, and use `ASSERT_*` when continuing after failure doesn't make sense. For example, the second assertion in the `Dequeue` test is `ASSERT_NE(n, nullptr)`, as we need to dereference the pointer `n` later, which would lead to a segfault when `n` is `NULL`. When these tests run, the following happens: 1. GoogleTest constructs a `QueueTest` object (let's call it `t1`). 2. The first test (`IsEmptyInitially`) runs on `t1`. 3. `t1` is destructed. 4. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test. **Availability**: Linux, Windows, Mac. ## Invoking the Tests `TEST()` and `TEST_F()` implicitly register their tests with GoogleTest. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them. After defining your tests, you can run them with `RUN_ALL_TESTS()`, which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs *all tests* in your link unit--they can be from different test suites, or even different source files. When invoked, the `RUN_ALL_TESTS()` macro: * Saves the state of all GoogleTest flags. * Creates a test fixture object for the first test. * Initializes it via `SetUp()`. * Runs the test on the fixture object. * Cleans up the fixture via `TearDown()`. * Deletes the fixture. * Restores the state of all GoogleTest flags. * Repeats the above steps for the next test, until all tests have run. If a fatal failure happens the subsequent steps will be skipped. {: .callout .important} > IMPORTANT: You must **not** ignore the return value of `RUN_ALL_TESTS()`, or > you will get a compiler error. The rationale for this design is that the > automated testing service determines whether a test has passed based on its > exit code, not on its stdout/stderr output; thus your `main()` function must > return the value of `RUN_ALL_TESTS()`. > > Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than > once conflicts with some advanced GoogleTest features (e.g., thread-safe > [death tests](advanced.md#death-tests)) and thus is not supported. **Availability**: Linux, Windows, Mac. ## Writing the main() Function Most users should *not* need to write their own `main` function and instead link with `gtest_main` (as opposed to with `gtest`), which defines a suitable entry point. See the end of this section for details. The remainder of this section should only apply when you need to do something custom before the tests run that cannot be expressed within the framework of fixtures and test suites. If you write your own `main` function, it should return the value of `RUN_ALL_TESTS()`. You can start from this boilerplate: ```c++ #include "this/package/foo.h" #include namespace my { namespace project { namespace { // The fixture for testing class Foo. class FooTest : public testing::Test { protected: // You can remove any or all of the following functions if their bodies would // be empty. FooTest() { // You can do set-up work for each test here. } ~FooTest() override { // You can do clean-up work that doesn't throw exceptions here. } // If the constructor and destructor are not enough for setting up // and cleaning up each test, you can define the following methods: void SetUp() override { // Code here will be called immediately after the constructor (right // before each test). } void TearDown() override { // Code here will be called immediately after each test (right // before the destructor). } // Class members declared here can be used by all tests in the test suite // for Foo. }; // Tests that the Foo::Bar() method does Abc. TEST_F(FooTest, MethodBarDoesAbc) { const std::string input_filepath = "this/package/testdata/myinputfile.dat"; const std::string output_filepath = "this/package/testdata/myoutputfile.dat"; Foo f; EXPECT_EQ(f.Bar(input_filepath, output_filepath), 0); } // Tests that Foo does Xyz. TEST_F(FooTest, DoesXyz) { // Exercises the Xyz feature of Foo. } } // namespace } // namespace project } // namespace my int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` The `testing::InitGoogleTest()` function parses the command line for GoogleTest flags, and removes all recognized flags. This allows the user to control a test program's behavior via various flags, which we'll cover in the [AdvancedGuide](advanced.md). You **must** call this function before calling `RUN_ALL_TESTS()`, or the flags won't be properly initialized. On Windows, `InitGoogleTest()` also works with wide strings, so it can be used in programs compiled in `UNICODE` mode as well. But maybe you think that writing all those `main` functions is too much work? We agree with you completely, and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with the `gtest_main` library and you are good to go. {: .callout .note} NOTE: `ParseGUnitFlags()` is deprecated in favor of `InitGoogleTest()`. ## Known Limitations * Google Test is designed to be thread-safe. The implementation is thread-safe on systems where the `pthreads` library is available. It is currently *unsafe* to use Google Test assertions from two threads concurrently on other systems (e.g. Windows). In most tests this is not an issue as usually the assertions are done in the main thread. If you want to help, you can volunteer to implement the necessary synchronization primitives in `gtest-port.h` for your platform. gperftools-gperftools-2.18/vendor/googletest/docs/quickstart-bazel.md000066400000000000000000000116621513545575200262440ustar00rootroot00000000000000# Quickstart: Building with Bazel This tutorial aims to get you up and running with GoogleTest using the Bazel build system. If you're using GoogleTest for the first time or need a refresher, we recommend this tutorial as a starting point. ## Prerequisites To complete this tutorial, you'll need: * A compatible operating system (e.g. Linux, macOS, Windows). * A compatible C++ compiler that supports at least C++17. * [Bazel](https://bazel.build/) 7.0 or higher, the preferred build system used by the GoogleTest team. See [Supported Platforms](platforms.md) for more information about platforms compatible with GoogleTest. If you don't already have Bazel installed, see the [Bazel installation guide](https://bazel.build/install). {: .callout .note} Note: The terminal commands in this tutorial show a Unix shell prompt, but the commands work on the Windows command line as well. ## Set up a Bazel workspace A [Bazel workspace](https://docs.bazel.build/versions/main/build-ref.html#workspace) is a directory on your filesystem that you use to manage source files for the software you want to build. Each workspace directory has a text file named `MODULE.bazel` which may be empty, or may contain references to external dependencies required to build the outputs. First, create a directory for your workspace: ``` $ mkdir my_workspace && cd my_workspace ``` Next, you’ll create the `MODULE.bazel` file to specify dependencies. As of Bazel 7.0, the recommended way to consume GoogleTest is through the [Bazel Central Registry](https://registry.bazel.build/modules/googletest). To do this, create a `MODULE.bazel` file in the root directory of your Bazel workspace with the following content: ``` # MODULE.bazel # Choose the most recent version available at # https://registry.bazel.build/modules/googletest bazel_dep(name = "googletest", version = "1.17.0") ``` Now you're ready to build C++ code that uses GoogleTest. ## Create and run a binary With your Bazel workspace set up, you can now use GoogleTest code within your own project. As an example, create a file named `hello_test.cc` in your `my_workspace` directory with the following contents: ```cpp #include // Demonstrate some basic assertions. TEST(HelloTest, BasicAssertions) { // Expect two strings not to be equal. EXPECT_STRNE("hello", "world"); // Expect equality. EXPECT_EQ(7 * 6, 42); } ``` GoogleTest provides [assertions](primer.md#assertions) that you use to test the behavior of your code. The above sample includes the main GoogleTest header file and demonstrates some basic assertions. To build the code, create a file named `BUILD` in the same directory with the following contents: ``` cc_test( name = "hello_test", size = "small", srcs = ["hello_test.cc"], deps = [ "@googletest//:gtest", "@googletest//:gtest_main", ], ) ``` This `cc_test` rule declares the C++ test binary you want to build, and links to the GoogleTest library (`@googletest//:gtest"`) and the GoogleTest `main()` function (`@googletest//:gtest_main`). For more information about Bazel `BUILD` files, see the [Bazel C++ Tutorial](https://docs.bazel.build/versions/main/tutorial/cpp.html). {: .callout .note} NOTE: In the example below, we assume Clang or GCC and set `--cxxopt=-std=c++17` to ensure that GoogleTest is compiled as C++17 instead of the compiler's default setting. For MSVC, the equivalent would be `--cxxopt=/std:c++17`. See [Supported Platforms](platforms.md) for more details on supported language versions. Now you can build and run your test:
$ bazel test --cxxopt=-std=c++17 --test_output=all //:hello_test
INFO: Analyzed target //:hello_test (26 packages loaded, 362 targets configured).
INFO: Found 1 test target...
INFO: From Testing //:hello_test:
==================== Test output for //:hello_test:
Running main() from gmock_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from HelloTest
[ RUN      ] HelloTest.BasicAssertions
[       OK ] HelloTest.BasicAssertions (0 ms)
[----------] 1 test from HelloTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.
================================================================================
Target //:hello_test up-to-date:
  bazel-bin/hello_test
INFO: Elapsed time: 4.190s, Critical Path: 3.05s
INFO: 27 processes: 8 internal, 19 linux-sandbox.
INFO: Build completed successfully, 27 total actions
//:hello_test                                                     PASSED in 0.1s

INFO: Build completed successfully, 27 total actions
Congratulations! You've successfully built and run a test binary using GoogleTest. ## Next steps * [Check out the Primer](primer.md) to start learning how to write simple tests. * [See the code samples](samples.md) for more examples showing how to use a variety of GoogleTest features. gperftools-gperftools-2.18/vendor/googletest/docs/quickstart-cmake.md000066400000000000000000000117511513545575200262260ustar00rootroot00000000000000# Quickstart: Building with CMake This tutorial aims to get you up and running with GoogleTest using CMake. If you're using GoogleTest for the first time or need a refresher, we recommend this tutorial as a starting point. If your project uses Bazel, see the [Quickstart for Bazel](quickstart-bazel.md) instead. ## Prerequisites To complete this tutorial, you'll need: * A compatible operating system (e.g. Linux, macOS, Windows). * A compatible C++ compiler that supports at least C++17. * [CMake](https://cmake.org/) and a compatible build tool for building the project. * Compatible build tools include [Make](https://www.gnu.org/software/make/), [Ninja](https://ninja-build.org/), and others - see [CMake Generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) for more information. See [Supported Platforms](platforms.md) for more information about platforms compatible with GoogleTest. If you don't already have CMake installed, see the [CMake installation guide](https://cmake.org/install). {: .callout .note} Note: The terminal commands in this tutorial show a Unix shell prompt, but the commands work on the Windows command line as well. ## Set up a project CMake uses a file named `CMakeLists.txt` to configure the build system for a project. You'll use this file to set up your project and declare a dependency on GoogleTest. First, create a directory for your project: ``` $ mkdir my_project && cd my_project ``` Next, you'll create the `CMakeLists.txt` file and declare a dependency on GoogleTest. There are many ways to express dependencies in the CMake ecosystem; in this quickstart, you'll use the [`FetchContent` CMake module](https://cmake.org/cmake/help/latest/module/FetchContent.html). To do this, in your project directory (`my_project`), create a file named `CMakeLists.txt` with the following contents: ```cmake cmake_minimum_required(VERSION 3.14) project(my_project) # GoogleTest requires at least C++17 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) include(FetchContent) FetchContent_Declare( googletest URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip ) # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) ``` The above configuration declares a dependency on GoogleTest which is downloaded from GitHub. In the above example, `03597a01ee50ed33e9dfd640b249b4be3799d395` is the Git commit hash of the GoogleTest version to use; we recommend updating the hash often to point to the latest version. For more information about how to create `CMakeLists.txt` files, see the [CMake Tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/index.html). ## Create and run a binary With GoogleTest declared as a dependency, you can use GoogleTest code within your own project. As an example, create a file named `hello_test.cc` in your `my_project` directory with the following contents: ```cpp #include // Demonstrate some basic assertions. TEST(HelloTest, BasicAssertions) { // Expect two strings not to be equal. EXPECT_STRNE("hello", "world"); // Expect equality. EXPECT_EQ(7 * 6, 42); } ``` GoogleTest provides [assertions](primer.md#assertions) that you use to test the behavior of your code. The above sample includes the main GoogleTest header file and demonstrates some basic assertions. To build the code, add the following to the end of your `CMakeLists.txt` file: ```cmake enable_testing() add_executable( hello_test hello_test.cc ) target_link_libraries( hello_test GTest::gtest_main ) include(GoogleTest) gtest_discover_tests(hello_test) ``` The above configuration enables testing in CMake, declares the C++ test binary you want to build (`hello_test`), and links it to GoogleTest (`gtest_main`). The last two lines enable CMake's test runner to discover the tests included in the binary, using the [`GoogleTest` CMake module](https://cmake.org/cmake/help/git-stage/module/GoogleTest.html). Now you can build and run your test:
my_project$ cmake -S . -B build
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
...
-- Build files have been written to: .../my_project/build

my_project$ cmake --build build
Scanning dependencies of target gtest
...
[100%] Built target gmock_main

my_project$ cd build && ctest
Test project .../my_project/build
    Start 1: HelloTest.BasicAssertions
1/1 Test #1: HelloTest.BasicAssertions ........   Passed    0.00 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.01 sec
Congratulations! You've successfully built and run a test binary using GoogleTest. ## Next steps * [Check out the Primer](primer.md) to start learning how to write simple tests. * [See the code samples](samples.md) for more examples showing how to use a variety of GoogleTest features. gperftools-gperftools-2.18/vendor/googletest/docs/reference/000077500000000000000000000000001513545575200243655ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/docs/reference/actions.md000066400000000000000000000155541513545575200263610ustar00rootroot00000000000000# Actions Reference [**Actions**](../gmock_for_dummies.md#actions-what-should-it-do) specify what a mock function should do when invoked. This page lists the built-in actions provided by GoogleTest. All actions are defined in the `::testing` namespace. ## Returning a Value | Action | Description | | :-------------------------------- | :-------------------------------------------- | | `Return()` | Return from a `void` mock function. | | `Return(value)` | Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed. | | `ReturnArg()` | Return the `N`-th (0-based) argument. | | `ReturnNew(a1, ..., ak)` | Return `new T(a1, ..., ak)`; a different object is created each time. | | `ReturnNull()` | Return a null pointer. | | `ReturnPointee(ptr)` | Return the value pointed to by `ptr`. | | `ReturnRef(variable)` | Return a reference to `variable`. | | `ReturnRefOfCopy(value)` | Return a reference to a copy of `value`; the copy lives as long as the action. | | `ReturnRoundRobin({a1, ..., ak})` | Each call will return the next `ai` in the list, starting at the beginning when the end of the list is reached. | ## Side Effects | Action | Description | | :--------------------------------- | :-------------------------------------- | | `Assign(&variable, value)` | Assign `value` to variable. | | `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | | `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer` by copy-assignment. | | `SaveArgByMove(pointer)` | Save the `N`-th (0-based) argument to `*pointer` by move-assignment. | | `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | | `SetArgReferee(value)` | Assign `value` to the variable referenced by the `N`-th (0-based) argument. | | `SetArgPointee(value)` | Assign `value` to the variable pointed by the `N`-th (0-based) argument. | | `SetArgumentPointee(value)` | Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0. | | `SetArrayArgument(first, last)` | Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range. | | `SetErrnoAndReturn(error, value)` | Set `errno` to `error` and return `value`. | | `Throw(exception)` | Throws the given exception, which can be any copyable value. Available since v1.1.0. | ## Using a Function, Functor, or Lambda as an Action In the following, by "callable" we mean a free function, `std::function`, functor, or lambda. | Action | Description | | :---------------------------------- | :------------------------------------- | | `f` | Invoke `f` with the arguments passed to the mock function, where `f` is a callable. | | `Invoke(f)` | Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor. | | `Invoke(object_pointer, &class::method)` | Invoke the method on the object with the arguments passed to the mock function. | | `InvokeWithoutArgs(f)` | Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | | `InvokeWithoutArgs(object_pointer, &class::method)` | Invoke the method on the object, which takes no arguments. | | `InvokeArgument(arg1, arg2, ..., argk)` | Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments. | The return value of the invoked function (except `InvokeArgument`) is used as the return value of the action. When defining a callable to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: ```cpp using ::testing::Invoke; double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); ``` `Invoke(callback)` and `InvokeWithoutArgs(callback)` take ownership of `callback`, which must be permanent. The type of `callback` must be a base callback type instead of a derived one, e.g. ```cpp BlockingClosure* done = new BlockingClosure; ... Invoke(done) ...; // This won't compile! Closure* done2 = new BlockingClosure; ... Invoke(done2) ...; // This works. ``` In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `std::ref()`. For example, ```cpp using ::testing::InvokeArgument; ... InvokeArgument<2>(5, string("Hi"), std::ref(foo)) ``` calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. ## Default Action | Action | Description | | :------------ | :----------------------------------------------------- | | `DoDefault()` | Do the default action (specified by `ON_CALL()` or the built-in one). | {: .callout .note} **Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. ## Composite Actions | Action | Description | | :----------------------------- | :------------------------------------------ | | `DoAll(a1, a2, ..., an)` | Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void and will receive a readonly view of the arguments. | | `IgnoreResult(a)` | Perform action `a` and ignore its result. `a` must not return void. | | `WithArg(a)` | Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | | `WithArgs(a)` | Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | | `WithoutArgs(a)` | Perform action `a` without any arguments. | ## Defining Actions | Macro | Description | | :--------------------------------- | :-------------------------------------- | | `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | | `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | | `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | The `ACTION*` macros cannot be used inside a function or class. gperftools-gperftools-2.18/vendor/googletest/docs/reference/assertions.md000066400000000000000000000527271513545575200271160ustar00rootroot00000000000000# Assertions Reference This page lists the assertion macros provided by GoogleTest for verifying code behavior. To use them, add `#include `. The majority of the macros listed below come as a pair with an `EXPECT_` variant and an `ASSERT_` variant. Upon failure, `EXPECT_` macros generate nonfatal failures and allow the current function to continue running, while `ASSERT_` macros generate fatal failures and abort the current function. All assertion macros support streaming a custom failure message into them with the `<<` operator, for example: ```cpp EXPECT_TRUE(my_condition) << "My condition is not true"; ``` Anything that can be streamed to an `ostream` can be streamed to an assertion macro—in particular, C strings and string objects. If a wide string (`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is streamed to an assertion, it will be translated to UTF-8 when printed. ## Explicit Success and Failure {#success-failure} The assertions in this section generate a success or failure directly instead of testing a value or expression. These are useful when control flow, rather than a Boolean expression, determines the test's success or failure, as shown by the following example: ```c++ switch(expression) { case 1: ... some checks ... case 2: ... some other checks ... default: FAIL() << "We shouldn't get here."; } ``` ### SUCCEED {#SUCCEED} `SUCCEED()` Generates a success. This *does not* make the overall test succeed. A test is considered successful only if none of its assertions fail during its execution. The `SUCCEED` assertion is purely documentary and currently doesn't generate any user-visible output. However, we may add `SUCCEED` messages to GoogleTest output in the future. ### FAIL {#FAIL} `FAIL()` Generates a fatal failure, which returns from the current function. Can only be used in functions that return `void`. See [Assertion Placement](../advanced.md#assertion-placement) for more information. ### ADD_FAILURE {#ADD_FAILURE} `ADD_FAILURE()` Generates a nonfatal failure, which allows the current function to continue running. ### ADD_FAILURE_AT {#ADD_FAILURE_AT} `ADD_FAILURE_AT(`*`file_path`*`,`*`line_number`*`)` Generates a nonfatal failure at the file and line number specified. ## Generalized Assertion {#generalized} The following assertion allows [matchers](matchers.md) to be used to verify values. ### EXPECT_THAT {#EXPECT_THAT} `EXPECT_THAT(`*`value`*`,`*`matcher`*`)` \ `ASSERT_THAT(`*`value`*`,`*`matcher`*`)` Verifies that *`value`* matches the [matcher](matchers.md) *`matcher`*. For example, the following code verifies that the string `value1` starts with `"Hello"`, `value2` matches a regular expression, and `value3` is between 5 and 10: ```cpp #include using ::testing::AllOf; using ::testing::Gt; using ::testing::Lt; using ::testing::MatchesRegex; using ::testing::StartsWith; ... EXPECT_THAT(value1, StartsWith("Hello")); EXPECT_THAT(value2, MatchesRegex("Line \\d+")); ASSERT_THAT(value3, AllOf(Gt(5), Lt(10))); ``` Matchers enable assertions of this form to read like English and generate informative failure messages. For example, if the above assertion on `value1` fails, the resulting message will be similar to the following: ``` Value of: value1 Actual: "Hi, world!" Expected: starts with "Hello" ``` GoogleTest provides a built-in library of matchers—see the [Matchers Reference](matchers.md). It is also possible to write your own matchers—see [Writing New Matchers Quickly](../gmock_cook_book.md#NewMatchers). The use of matchers makes `EXPECT_THAT` a powerful, extensible assertion. *The idea for this assertion was borrowed from Joe Walnes' Hamcrest project, which adds `assertThat()` to JUnit.* ## Boolean Conditions {#boolean} The following assertions test Boolean conditions. ### EXPECT_TRUE {#EXPECT_TRUE} `EXPECT_TRUE(`*`condition`*`)` \ `ASSERT_TRUE(`*`condition`*`)` Verifies that *`condition`* is true. ### EXPECT_FALSE {#EXPECT_FALSE} `EXPECT_FALSE(`*`condition`*`)` \ `ASSERT_FALSE(`*`condition`*`)` Verifies that *`condition`* is false. ## Binary Comparison {#binary-comparison} The following assertions compare two values. The value arguments must be comparable by the assertion's comparison operator, otherwise a compiler error will result. If an argument supports the `<<` operator, it will be called to print the argument when the assertion fails. Otherwise, GoogleTest will attempt to print them in the best way it can—see [Teaching GoogleTest How to Print Your Values](../advanced.md#teaching-googletest-how-to-print-your-values). Arguments are always evaluated exactly once, so it's OK for the arguments to have side effects. However, the argument evaluation order is undefined and programs should not depend on any particular argument evaluation order. These assertions work with both narrow and wide string objects (`string` and `wstring`). See also the [Floating-Point Comparison](#floating-point) assertions to compare floating-point numbers and avoid problems caused by rounding. ### EXPECT_EQ {#EXPECT_EQ} `EXPECT_EQ(`*`val1`*`,`*`val2`*`)` \ `ASSERT_EQ(`*`val1`*`,`*`val2`*`)` Verifies that *`val1`*`==`*`val2`*. Does pointer equality on pointers. If used on two C strings, it tests if they are in the same memory location, not if they have the same value. Use [`EXPECT_STREQ`](#EXPECT_STREQ) to compare C strings (e.g. `const char*`) by value. When comparing a pointer to `NULL`, use `EXPECT_EQ(`*`ptr`*`, nullptr)` instead of `EXPECT_EQ(`*`ptr`*`, NULL)`. ### EXPECT_NE {#EXPECT_NE} `EXPECT_NE(`*`val1`*`,`*`val2`*`)` \ `ASSERT_NE(`*`val1`*`,`*`val2`*`)` Verifies that *`val1`*`!=`*`val2`*. Does pointer equality on pointers. If used on two C strings, it tests if they are in different memory locations, not if they have different values. Use [`EXPECT_STRNE`](#EXPECT_STRNE) to compare C strings (e.g. `const char*`) by value. When comparing a pointer to `NULL`, use `EXPECT_NE(`*`ptr`*`, nullptr)` instead of `EXPECT_NE(`*`ptr`*`, NULL)`. ### EXPECT_LT {#EXPECT_LT} `EXPECT_LT(`*`val1`*`,`*`val2`*`)` \ `ASSERT_LT(`*`val1`*`,`*`val2`*`)` Verifies that *`val1`*`<`*`val2`*. ### EXPECT_LE {#EXPECT_LE} `EXPECT_LE(`*`val1`*`,`*`val2`*`)` \ `ASSERT_LE(`*`val1`*`,`*`val2`*`)` Verifies that *`val1`*`<=`*`val2`*. ### EXPECT_GT {#EXPECT_GT} `EXPECT_GT(`*`val1`*`,`*`val2`*`)` \ `ASSERT_GT(`*`val1`*`,`*`val2`*`)` Verifies that *`val1`*`>`*`val2`*. ### EXPECT_GE {#EXPECT_GE} `EXPECT_GE(`*`val1`*`,`*`val2`*`)` \ `ASSERT_GE(`*`val1`*`,`*`val2`*`)` Verifies that *`val1`*`>=`*`val2`*. ## String Comparison {#c-strings} The following assertions compare two **C strings**. To compare two `string` objects, use [`EXPECT_EQ`](#EXPECT_EQ) or [`EXPECT_NE`](#EXPECT_NE) instead. These assertions also accept wide C strings (`wchar_t*`). If a comparison of two wide strings fails, their values will be printed as UTF-8 narrow strings. To compare a C string with `NULL`, use `EXPECT_EQ(`*`c_string`*`, nullptr)` or `EXPECT_NE(`*`c_string`*`, nullptr)`. ### EXPECT_STREQ {#EXPECT_STREQ} `EXPECT_STREQ(`*`str1`*`,`*`str2`*`)` \ `ASSERT_STREQ(`*`str1`*`,`*`str2`*`)` Verifies that the two C strings *`str1`* and *`str2`* have the same contents. ### EXPECT_STRNE {#EXPECT_STRNE} `EXPECT_STRNE(`*`str1`*`,`*`str2`*`)` \ `ASSERT_STRNE(`*`str1`*`,`*`str2`*`)` Verifies that the two C strings *`str1`* and *`str2`* have different contents. ### EXPECT_STRCASEEQ {#EXPECT_STRCASEEQ} `EXPECT_STRCASEEQ(`*`str1`*`,`*`str2`*`)` \ `ASSERT_STRCASEEQ(`*`str1`*`,`*`str2`*`)` Verifies that the two C strings *`str1`* and *`str2`* have the same contents, ignoring case. ### EXPECT_STRCASENE {#EXPECT_STRCASENE} `EXPECT_STRCASENE(`*`str1`*`,`*`str2`*`)` \ `ASSERT_STRCASENE(`*`str1`*`,`*`str2`*`)` Verifies that the two C strings *`str1`* and *`str2`* have different contents, ignoring case. ## Floating-Point Comparison {#floating-point} The following assertions compare two floating-point values. Due to rounding errors, it is very unlikely that two floating-point values will match exactly, so `EXPECT_EQ` is not suitable. In general, for floating-point comparison to make sense, the user needs to carefully choose the error bound. GoogleTest also provides assertions that use a default error bound based on Units in the Last Place (ULPs). To learn more about ULPs, see the article [Comparing Floating Point Numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). ### EXPECT_FLOAT_EQ {#EXPECT_FLOAT_EQ} `EXPECT_FLOAT_EQ(`*`val1`*`,`*`val2`*`)` \ `ASSERT_FLOAT_EQ(`*`val1`*`,`*`val2`*`)` Verifies that the two `float` values *`val1`* and *`val2`* are approximately equal, to within 4 ULPs from each other. Infinity and the largest finite float value are considered to be one ULP apart. ### EXPECT_DOUBLE_EQ {#EXPECT_DOUBLE_EQ} `EXPECT_DOUBLE_EQ(`*`val1`*`,`*`val2`*`)` \ `ASSERT_DOUBLE_EQ(`*`val1`*`,`*`val2`*`)` Verifies that the two `double` values *`val1`* and *`val2`* are approximately equal, to within 4 ULPs from each other. Infinity and the largest finite double value are considered to be one ULP apart. ### EXPECT_NEAR {#EXPECT_NEAR} `EXPECT_NEAR(`*`val1`*`,`*`val2`*`,`*`abs_error`*`)` \ `ASSERT_NEAR(`*`val1`*`,`*`val2`*`,`*`abs_error`*`)` Verifies that the difference between *`val1`* and *`val2`* does not exceed the absolute error bound *`abs_error`*. If *`val`* and *`val2`* are both infinity of the same sign, the difference is considered to be 0. Otherwise, if either value is infinity, the difference is considered to be infinity. All non-NaN values (including infinity) are considered to not exceed an *`abs_error`* of infinity. ## Exception Assertions {#exceptions} The following assertions verify that a piece of code throws, or does not throw, an exception. Usage requires exceptions to be enabled in the build environment. Note that the piece of code under test can be a compound statement, for example: ```cpp EXPECT_NO_THROW({ int n = 5; DoSomething(&n); }); ``` ### EXPECT_THROW {#EXPECT_THROW} `EXPECT_THROW(`*`statement`*`,`*`exception_type`*`)` \ `ASSERT_THROW(`*`statement`*`,`*`exception_type`*`)` Verifies that *`statement`* throws an exception of type *`exception_type`*. ### EXPECT_ANY_THROW {#EXPECT_ANY_THROW} `EXPECT_ANY_THROW(`*`statement`*`)` \ `ASSERT_ANY_THROW(`*`statement`*`)` Verifies that *`statement`* throws an exception of any type. ### EXPECT_NO_THROW {#EXPECT_NO_THROW} `EXPECT_NO_THROW(`*`statement`*`)` \ `ASSERT_NO_THROW(`*`statement`*`)` Verifies that *`statement`* does not throw any exception. ## Predicate Assertions {#predicates} The following assertions enable more complex predicates to be verified while printing a more clear failure message than if `EXPECT_TRUE` were used alone. ### EXPECT_PRED* {#EXPECT_PRED} `EXPECT_PRED1(`*`pred`*`,`*`val1`*`)` \ `EXPECT_PRED2(`*`pred`*`,`*`val1`*`,`*`val2`*`)` \ `EXPECT_PRED3(`*`pred`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`)` \ `EXPECT_PRED4(`*`pred`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`,`*`val4`*`)` \ `EXPECT_PRED5(`*`pred`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`,`*`val4`*`,`*`val5`*`)` `ASSERT_PRED1(`*`pred`*`,`*`val1`*`)` \ `ASSERT_PRED2(`*`pred`*`,`*`val1`*`,`*`val2`*`)` \ `ASSERT_PRED3(`*`pred`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`)` \ `ASSERT_PRED4(`*`pred`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`,`*`val4`*`)` \ `ASSERT_PRED5(`*`pred`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`,`*`val4`*`,`*`val5`*`)` Verifies that the predicate *`pred`* returns `true` when passed the given values as arguments. The parameter *`pred`* is a function or functor that accepts as many arguments as the corresponding macro accepts values. If *`pred`* returns `true` for the given arguments, the assertion succeeds, otherwise the assertion fails. When the assertion fails, it prints the value of each argument. Arguments are always evaluated exactly once. As an example, see the following code: ```cpp // Returns true if m and n have no common divisors except 1. bool MutuallyPrime(int m, int n) { ... } ... const int a = 3; const int b = 4; const int c = 10; ... EXPECT_PRED2(MutuallyPrime, a, b); // Succeeds EXPECT_PRED2(MutuallyPrime, b, c); // Fails ``` In the above example, the first assertion succeeds, and the second fails with the following message: ``` MutuallyPrime(b, c) is false, where b is 4 c is 10 ``` Note that if the given predicate is an overloaded function or a function template, the assertion macro might not be able to determine which version to use, and it might be necessary to explicitly specify the type of the function. For example, for a Boolean function `IsPositive()` overloaded to take either a single `int` or `double` argument, it would be necessary to write one of the following: ```cpp EXPECT_PRED1(static_cast(IsPositive), 5); EXPECT_PRED1(static_cast(IsPositive), 3.14); ``` Writing simply `EXPECT_PRED1(IsPositive, 5);` would result in a compiler error. Similarly, to use a template function, specify the template arguments: ```cpp template bool IsNegative(T x) { return x < 0; } ... EXPECT_PRED1(IsNegative, -5); // Must specify type for IsNegative ``` If a template has multiple parameters, wrap the predicate in parentheses so the macro arguments are parsed correctly: ```cpp ASSERT_PRED2((MyPredicate), 5, 0); ``` ### EXPECT_PRED_FORMAT* {#EXPECT_PRED_FORMAT} `EXPECT_PRED_FORMAT1(`*`pred_formatter`*`,`*`val1`*`)` \ `EXPECT_PRED_FORMAT2(`*`pred_formatter`*`,`*`val1`*`,`*`val2`*`)` \ `EXPECT_PRED_FORMAT3(`*`pred_formatter`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`)` \ `EXPECT_PRED_FORMAT4(`*`pred_formatter`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`,`*`val4`*`)` \ `EXPECT_PRED_FORMAT5(`*`pred_formatter`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`,`*`val4`*`,`*`val5`*`)` `ASSERT_PRED_FORMAT1(`*`pred_formatter`*`,`*`val1`*`)` \ `ASSERT_PRED_FORMAT2(`*`pred_formatter`*`,`*`val1`*`,`*`val2`*`)` \ `ASSERT_PRED_FORMAT3(`*`pred_formatter`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`)` \ `ASSERT_PRED_FORMAT4(`*`pred_formatter`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`,`*`val4`*`)` \ `ASSERT_PRED_FORMAT5(`*`pred_formatter`*`,`*`val1`*`,`*`val2`*`,`*`val3`*`,`*`val4`*`,`*`val5`*`)` Verifies that the predicate *`pred_formatter`* succeeds when passed the given values as arguments. The parameter *`pred_formatter`* is a *predicate-formatter*, which is a function or functor with the signature: ```cpp testing::AssertionResult PredicateFormatter(const char* expr1, const char* expr2, ... const char* exprn, T1 val1, T2 val2, ... Tn valn); ``` where *`val1`*, *`val2`*, ..., *`valn`* are the values of the predicate arguments, and *`expr1`*, *`expr2`*, ..., *`exprn`* are the corresponding expressions as they appear in the source code. The types `T1`, `T2`, ..., `Tn` can be either value types or reference types; if an argument has type `T`, it can be declared as either `T` or `const T&`, whichever is appropriate. For more about the return type `testing::AssertionResult`, see [Using a Function That Returns an AssertionResult](../advanced.md#using-a-function-that-returns-an-assertionresult). As an example, see the following code: ```cpp // Returns the smallest prime common divisor of m and n, // or 1 when m and n are mutually prime. int SmallestPrimeCommonDivisor(int m, int n) { ... } // Returns true if m and n have no common divisors except 1. bool MutuallyPrime(int m, int n) { ... } // A predicate-formatter for asserting that two integers are mutually prime. testing::AssertionResult AssertMutuallyPrime(const char* m_expr, const char* n_expr, int m, int n) { if (MutuallyPrime(m, n)) return testing::AssertionSuccess(); return testing::AssertionFailure() << m_expr << " and " << n_expr << " (" << m << " and " << n << ") are not mutually prime, " << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); } ... const int a = 3; const int b = 4; const int c = 10; ... EXPECT_PRED_FORMAT2(AssertMutuallyPrime, a, b); // Succeeds EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c); // Fails ``` In the above example, the final assertion fails and the predicate-formatter produces the following failure message: ``` b and c (4 and 10) are not mutually prime, as they have a common divisor 2 ``` ## Windows HRESULT Assertions {#HRESULT} The following assertions test for `HRESULT` success or failure. For example: ```cpp CComPtr shell; ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application")); CComVariant empty; ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty)); ``` The generated output contains the human-readable error message associated with the returned `HRESULT` code. ### EXPECT_HRESULT_SUCCEEDED {#EXPECT_HRESULT_SUCCEEDED} `EXPECT_HRESULT_SUCCEEDED(`*`expression`*`)` \ `ASSERT_HRESULT_SUCCEEDED(`*`expression`*`)` Verifies that *`expression`* is a success `HRESULT`. ### EXPECT_HRESULT_FAILED {#EXPECT_HRESULT_FAILED} `EXPECT_HRESULT_FAILED(`*`expression`*`)` \ `ASSERT_HRESULT_FAILED(`*`expression`*`)` Verifies that *`expression`* is a failure `HRESULT`. ## Death Assertions {#death} The following assertions verify that a piece of code causes the process to terminate. For context, see [Death Tests](../advanced.md#death-tests). These assertions spawn a new process and execute the code under test in that process. How that happens depends on the platform and the variable `::testing::GTEST_FLAG(death_test_style)`, which is initialized from the command-line flag `--gtest_death_test_style`. * On POSIX systems, `fork()` (or `clone()` on Linux) is used to spawn the child, after which: * If the variable's value is `"fast"`, the death test statement is immediately executed. * If the variable's value is `"threadsafe"`, the child process re-executes the unit test binary just as it was originally invoked, but with some extra flags to cause just the single death test under consideration to be run. * On Windows, the child is spawned using the `CreateProcess()` API, and re-executes the binary to cause just the single death test under consideration to be run - much like the `"threadsafe"` mode on POSIX. Other values for the variable are illegal and will cause the death test to fail. Currently, the flag's default value is **`"fast"`**. If the death test statement runs to completion without dying, the child process will nonetheless terminate, and the assertion fails. Note that the piece of code under test can be a compound statement, for example: ```cpp EXPECT_DEATH({ int n = 5; DoSomething(&n); }, "Error on line .* of DoSomething()"); ``` ### EXPECT_DEATH {#EXPECT_DEATH} `EXPECT_DEATH(`*`statement`*`,`*`matcher`*`)` \ `ASSERT_DEATH(`*`statement`*`,`*`matcher`*`)` Verifies that *`statement`* causes the process to terminate with a nonzero exit status and produces `stderr` output that matches *`matcher`*. The parameter *`matcher`* is either a [matcher](matchers.md) for a `const std::string&`, or a regular expression (see [Regular Expression Syntax](../advanced.md#regular-expression-syntax))—a bare string *`s`* (with no matcher) is treated as [`ContainsRegex(s)`](matchers.md#string-matchers), **not** [`Eq(s)`](matchers.md#generic-comparison). For example, the following code verifies that calling `DoSomething(42)` causes the process to die with an error message that contains the text `My error`: ```cpp EXPECT_DEATH(DoSomething(42), "My error"); ``` ### EXPECT_DEATH_IF_SUPPORTED {#EXPECT_DEATH_IF_SUPPORTED} `EXPECT_DEATH_IF_SUPPORTED(`*`statement`*`,`*`matcher`*`)` \ `ASSERT_DEATH_IF_SUPPORTED(`*`statement`*`,`*`matcher`*`)` If death tests are supported, behaves the same as [`EXPECT_DEATH`](#EXPECT_DEATH). Otherwise, verifies nothing. ### EXPECT_DEBUG_DEATH {#EXPECT_DEBUG_DEATH} `EXPECT_DEBUG_DEATH(`*`statement`*`,`*`matcher`*`)` \ `ASSERT_DEBUG_DEATH(`*`statement`*`,`*`matcher`*`)` In debug mode, behaves the same as [`EXPECT_DEATH`](#EXPECT_DEATH). When not in debug mode (i.e. `NDEBUG` is defined), just executes *`statement`*. ### EXPECT_EXIT {#EXPECT_EXIT} `EXPECT_EXIT(`*`statement`*`,`*`predicate`*`,`*`matcher`*`)` \ `ASSERT_EXIT(`*`statement`*`,`*`predicate`*`,`*`matcher`*`)` Verifies that *`statement`* causes the process to terminate with an exit status that satisfies *`predicate`*, and produces `stderr` output that matches *`matcher`*. The parameter *`predicate`* is a function or functor that accepts an `int` exit status and returns a `bool`. GoogleTest provides two predicates to handle common cases: ```cpp // Returns true if the program exited normally with the given exit status code. ::testing::ExitedWithCode(exit_code); // Returns true if the program was killed by the given signal. // Not available on Windows. ::testing::KilledBySignal(signal_number); ``` The parameter *`matcher`* is either a [matcher](matchers.md) for a `const std::string&`, or a regular expression (see [Regular Expression Syntax](../advanced.md#regular-expression-syntax))—a bare string *`s`* (with no matcher) is treated as [`ContainsRegex(s)`](matchers.md#string-matchers), **not** [`Eq(s)`](matchers.md#generic-comparison). For example, the following code verifies that calling `NormalExit()` causes the process to print a message containing the text `Success` to `stderr` and exit with exit status code 0: ```cpp EXPECT_EXIT(NormalExit(), testing::ExitedWithCode(0), "Success"); ``` gperftools-gperftools-2.18/vendor/googletest/docs/reference/matchers.md000066400000000000000000000540131513545575200265200ustar00rootroot00000000000000# Matchers Reference A **matcher** matches a *single* argument. You can use it inside `ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value directly using two macros: | Macro | Description | | :----------------------------------- | :------------------------------------ | | `EXPECT_THAT(actual_value, matcher)` | Asserts that `actual_value` matches `matcher`. | | `ASSERT_THAT(actual_value, matcher)` | The same as `EXPECT_THAT(actual_value, matcher)`, except that it generates a **fatal** failure. | {: .callout .warning} **WARNING:** Equality matching via `EXPECT_THAT(actual_value, expected_value)` is supported, however note that implicit conversions can cause surprising results. For example, `EXPECT_THAT(some_bool, "some string")` will compile and may pass unintentionally. **BEST PRACTICE:** Prefer to make the comparison explicit via `EXPECT_THAT(actual_value, Eq(expected_value))` or `EXPECT_EQ(actual_value, expected_value)`. Built-in matchers (where `argument` is the function argument, e.g. `actual_value` in the example above, or when used in the context of `EXPECT_CALL(mock_object, method(matchers))`, the arguments of `method`) are divided into several categories. All matchers are defined in the `::testing` namespace unless otherwise noted. ## Wildcard Matcher | Description :-------------------------- | :----------------------------------------------- `_` | `argument` can be any value of the correct type. `A()` or `An()` | `argument` can be any value of type `type`. ## Generic Comparison | Matcher | Description | | :--------------------- | :-------------------------------------------------- | | `Eq(value)` or `value` | `argument == value` | | `Ge(value)` | `argument >= value` | | `Gt(value)` | `argument > value` | | `Le(value)` | `argument <= value` | | `Lt(value)` | `argument < value` | | `Ne(value)` | `argument != value` | | `IsFalse()` | `argument` evaluates to `false` in a Boolean context. | | `DistanceFrom(target, m)` | The distance between `argument` and `target` (computed by `abs(argument - target)`) matches `m`. | | `DistanceFrom(target, get_distance, m)` | The distance between `argument` and `target` (computed by `get_distance(argument, target)`) matches `m`. | | `IsTrue()` | `argument` evaluates to `true` in a Boolean context. | | `IsNull()` | `argument` is a `NULL` pointer (raw or smart). | | `NotNull()` | `argument` is a non-null pointer (raw or smart). | | `Optional(m)` | `argument` is `optional<>` that contains a value matching `m`. (For testing whether an `optional<>` is set, check for equality with `nullopt`. You may need to use `Eq(nullopt)` if the inner type doesn't have `==`.)| | `VariantWith(m)` | `argument` is `variant<>` that holds the alternative of type T with a value matching `m`. | | `Ref(variable)` | `argument` is a reference to `variable`. | | `TypedEq(value)` | `argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded. | Except `Ref()`, these matchers make a *copy* of `value` in case it's modified or destructed later. If the compiler complains that `value` doesn't have a public copy constructor, try wrap it in `std::ref()`, e.g. `Eq(std::ref(non_copyable_value))`. If you do that, make sure `non_copyable_value` is not changed afterwards, or the meaning of your matcher will be changed. `IsTrue` and `IsFalse` are useful when you need to use a matcher, or for types that can be explicitly converted to Boolean, but are not implicitly converted to Boolean. In other cases, you can use the basic [`EXPECT_TRUE` and `EXPECT_FALSE`](assertions.md#boolean) assertions. ## Floating-Point Matchers {#FpMatchers} | Matcher | Description | | :------------------------------- | :--------------------------------- | | `DoubleEq(a_double)` | `argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal. | | `FloatEq(a_float)` | `argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | | `NanSensitiveDoubleEq(a_double)` | `argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | | `NanSensitiveFloatEq(a_float)` | `argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | | `IsNan()` | `argument` is any floating-point type with a NaN value. | The above matchers use ULP-based comparison (the same as used in googletest). They automatically pick a reasonable error bound based on the absolute value of the expected value. `DoubleEq()` and `FloatEq()` conform to the IEEE standard, which requires comparing two NaNs for equality to return false. The `NanSensitive*` version instead treats two NaNs as equal, which is often what a user wants. | Matcher | Description | | :------------------------------------------------ | :----------------------- | | `DoubleNear(a_double, max_abs_error)` | `argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | | `FloatNear(a_float, max_abs_error)` | `argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | | `NanSensitiveDoubleNear(a_double, max_abs_error)` | `argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. | | `NanSensitiveFloatNear(a_float, max_abs_error)` | `argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. | ## String Matchers The `argument` can be either a C string or a C++ string object: | Matcher | Description | | :---------------------- | :------------------------------------------------- | | `ContainsRegex(string)` | `argument` matches the given regular expression. | | `EndsWith(suffix)` | `argument` ends with string `suffix`. | | `HasSubstr(string)` | `argument` contains `string` as a sub-string. | | `IsEmpty()` | `argument` is an empty string. | | `MatchesRegex(string)` | `argument` matches the given regular expression with the match starting at the first character and ending at the last character. | | `StartsWith(prefix)` | `argument` starts with string `prefix`. | | `StrCaseEq(string)` | `argument` is equal to `string`, ignoring case. | | `StrCaseNe(string)` | `argument` is not equal to `string`, ignoring case. | | `StrEq(string)` | `argument` is equal to `string`. | | `StrNe(string)` | `argument` is not equal to `string`. | | `WhenBase64Unescaped(m)` | `argument` is a base-64 escaped string whose unescaped string matches `m`. The web-safe format from [RFC 4648](https://www.rfc-editor.org/rfc/rfc4648#section-5) is supported. | `ContainsRegex()` and `MatchesRegex()` take ownership of the `RE` object. They use the regular expression syntax defined [here](../advanced.md#regular-expression-syntax). All of these matchers, except `ContainsRegex()` and `MatchesRegex()` work for wide strings as well. ## Exception Matchers | Matcher | Description | | :---------------------------------------- | :------------------------------- | | `Throws()` | The `argument` is a callable object that, when called, throws an exception of the expected type `E`. | | `Throws(m)` | The `argument` is a callable object that, when called, throws an exception of type `E` that satisfies the matcher `m`. | | `ThrowsMessage(m)` | The `argument` is a callable object that, when called, throws an exception of type `E` with a message that satisfies the matcher `m`. | Examples: ```cpp auto argument = [] { throw std::runtime_error("error msg"); }; // Checks if the lambda throws a `std::runtime_error`. EXPECT_THAT(argument, Throws()); // Checks if the lambda throws a `std::runtime_error` with a specific message // that matches "error msg". EXPECT_THAT(argument, Throws(Property(&std::runtime_error::what, Eq("error msg")))); // Checks if the lambda throws a `std::runtime_error` with a message that // contains "msg". EXPECT_THAT(argument, ThrowsMessage(HasSubstr("msg"))); ``` ## Container Matchers Most STL-style containers support `==`, so you can use `Eq(expected_container)` or simply `expected_container` to match a container exactly. If you want to write the elements in-line, match them more flexibly, or get more informative messages, you can use: | Matcher | Description | | :---------------------------------------- | :------------------------------- | | `BeginEndDistanceIs(m)` | `argument` is a container whose `begin()` and `end()` iterators are separated by a number of increments matching `m`. E.g. `BeginEndDistanceIs(2)` or `BeginEndDistanceIs(Lt(2))`. For containers that define a `size()` method, `SizeIs(m)` may be more efficient. | | `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | | `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | | `Contains(e).Times(n)` | `argument` contains elements that match `e`, which can be either a value or a matcher, and the number of matches is `n`, which can be either a value or a matcher. Unlike the plain `Contains` and `Each` this allows to check for arbitrary occurrences including testing for absence with `Contains(e).Times(0)`. | | `Each(e)` | `argument` is a container where *every* element matches `e`, which can be either a value or a matcher. | | `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the *i*-th element matches `ei`, which can be a value or a matcher. | | `ElementsAreArray({e0, e1, ..., en})`, `ElementsAreArray(a_container)`, `ElementsAreArray(begin, end)`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, iterator range, or C-style array. | | `IsEmpty()` | `argument` is an empty container (`container.empty()`). | | `IsSubsetOf({e0, e1, ..., en})`, `IsSubsetOf(a_container)`, `IsSubsetOf(begin, end)`, `IsSubsetOf(array)`, or `IsSubsetOf(array, count)` | `argument` matches `UnorderedElementsAre(x0, x1, ..., xk)` for some subset `{x0, x1, ..., xk}` of the expected matchers. | | `IsSupersetOf({e0, e1, ..., en})`, `IsSupersetOf(a_container)`, `IsSupersetOf(begin, end)`, `IsSupersetOf(array)`, or `IsSupersetOf(array, count)` | Some subset of `argument` matches `UnorderedElementsAre(`expected matchers`)`. | | `Pointwise(m, container)`, `Pointwise(m, {e0, e1, ..., en})` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. | | `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. | | `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under *some* permutation of the elements, each element matches an `ei` (for a different `i`), which can be a value or a matcher. | | `UnorderedElementsAreArray({e0, e1, ..., en})`, `UnorderedElementsAreArray(a_container)`, `UnorderedElementsAreArray(begin, end)`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, iterator range, or C-style array. | | `UnorderedPointwise(m, container)`, `UnorderedPointwise(m, {e0, e1, ..., en})` | Like `Pointwise(m, container)`, but ignores the order of elements. | | `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(ElementsAre(1, 2, 3))` verifies that `argument` contains elements 1, 2, and 3, ignoring order. | | `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))`. | **Notes:** * These matchers can also match: 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and 2. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#MultiArgMatchers)). * The array being matched may be multi-dimensional (i.e. its elements can be arrays). * `m` in `Pointwise(m, ...)` and `UnorderedPointwise(m, ...)` should be a matcher for `::std::tuple` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==`, one might write: ```cpp MATCHER(FooEq, "") { return std::get<0>(arg).Equals(std::get<1>(arg)); } ... EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos)); ``` ## Member Matchers | Matcher | Description | | :------------------------------ | :----------------------------------------- | | `Field(&class::field, m)` | `argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. | | `Field(field_name, &class::field, m)` | The same as the two-parameter version, but provides a better error message. | | `Key(e)` | `argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`. | | `Pair(m1, m2)` | `argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | | `FieldsAre(m...)` | `argument` is a compatible object where each field matches piecewise with the matchers `m...`. A compatible object is any that supports the `std::tuple_size`+`get(obj)` protocol. In C++17 and up this also supports types compatible with structured bindings, like aggregates. | | `Property(&class::property, m)` | `argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. The method `property()` must take no argument and be declared as `const`. | | `Property(property_name, &class::property, m)` | The same as the two-parameter version, but provides a better error message. {: .callout .warning} Warning: Don't use `Property()` against member functions that you do not own, because taking addresses of functions is fragile and generally not part of the contract of the function. **Notes:** * You can use `FieldsAre()` to match any type that supports structured bindings, such as `std::tuple`, `std::pair`, `std::array`, and aggregate types. For example: ```cpp std::tuple my_tuple{7, "hello world"}; EXPECT_THAT(my_tuple, FieldsAre(Ge(0), HasSubstr("hello"))); struct MyStruct { int value = 42; std::string greeting = "aloha"; }; MyStruct s; EXPECT_THAT(s, FieldsAre(42, "aloha")); ``` ## Matching the Result of a Function, Functor, or Callback | Matcher | Description | | :--------------- | :------------------------------------------------ | | `ResultOf(f, m)` | `f(argument)` matches matcher `m`, where `f` is a function or functor. | | `ResultOf(result_description, f, m)` | The same as the two-parameter version, but provides a better error message. ## Pointer Matchers | Matcher | Description | | :------------------------ | :---------------------------------------------- | | `Address(m)` | the result of `std::addressof(argument)` matches `m`. | | `Pointee(m)` | `argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`. | | `Pointer(m)` | `argument` (either a smart pointer or a raw pointer) contains a pointer that matches `m`. `m` will match against the raw pointer regardless of the type of `argument`. | | `WhenDynamicCastTo(m)` | when `argument` is passed through `dynamic_cast()`, it matches matcher `m`. | ## Multi-argument Matchers {#MultiArgMatchers} Technically, all matchers match a *single* value. A "multi-argument" matcher is just one that matches a *tuple*. The following matchers can be used to match a tuple `(x, y)`: Matcher | Description :------ | :---------- `Eq()` | `x == y` `Ge()` | `x >= y` `Gt()` | `x > y` `Le()` | `x <= y` `Lt()` | `x < y` `Ne()` | `x != y` You can use the following selectors to pick a subset of the arguments (or reorder them) to participate in the matching: | Matcher | Description | | :------------------------- | :---------------------------------------------- | | `AllArgs(m)` | Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`. | | `Args(m)` | The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`. | ## Composite Matchers You can make a matcher from one or more other matchers: | Matcher | Description | | :------------------------------- | :-------------------------------------- | | `AllOf(m1, m2, ..., mn)` | `argument` matches all of the matchers `m1` to `mn`. | | `AllOfArray({m0, m1, ..., mn})`, `AllOfArray(a_container)`, `AllOfArray(begin, end)`, `AllOfArray(array)`, or `AllOfArray(array, count)` | The same as `AllOf()` except that the matchers come from an initializer list, STL-style container, iterator range, or C-style array. | | `AnyOf(m1, m2, ..., mn)` | `argument` matches at least one of the matchers `m1` to `mn`. | | `AnyOfArray({m0, m1, ..., mn})`, `AnyOfArray(a_container)`, `AnyOfArray(begin, end)`, `AnyOfArray(array)`, or `AnyOfArray(array, count)` | The same as `AnyOf()` except that the matchers come from an initializer list, STL-style container, iterator range, or C-style array. | | `Not(m)` | `argument` doesn't match matcher `m`. | | `Conditional(cond, m1, m2)` | Matches matcher `m1` if `cond` evaluates to true, else matches `m2`.| ## Adapters for Matchers | Matcher | Description | | :---------------------- | :------------------------------------ | | `MatcherCast(m)` | casts matcher `m` to type `Matcher`. | | `SafeMatcherCast(m)` | [safely casts](../gmock_cook_book.md#SafeMatcherCast) matcher `m` to type `Matcher`. | | `Truly(predicate)` | `predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor. | `AddressSatisfies(callback)` and `Truly(callback)` take ownership of `callback`, which must be a permanent callback. ## Using Matchers as Predicates {#MatchersAsPredicatesCheat} | Matcher | Description | | :---------------------------- | :------------------------------------------ | | `Matches(m)(value)` | evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor. | | `ExplainMatchResult(m, value, result_listener)` | evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | | `Value(value, m)` | evaluates to `true` if `value` matches `m`. | ## Defining Matchers | Macro | Description | | :----------------------------------- | :------------------------------------ | | `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | | `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a matcher `IsDivisibleBy(n)` to match a number divisible by `n`. | | `MATCHER_P2(IsBetween, a, b, absl::StrCat(negation ? "isn't" : "is", " between ", PrintToString(a), " and ", PrintToString(b))) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | **Notes:** 1. The `MATCHER*` macros cannot be used inside a function or class. 2. The matcher body must be *purely functional* (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). 3. You can use `PrintToString(x)` to convert a value `x` of any type to a string. 4. You can use `ExplainMatchResult()` in a custom matcher to wrap another matcher, for example: ```cpp MATCHER_P(NestedPropertyMatches, matcher, "") { return ExplainMatchResult(matcher, arg.nested().property(), result_listener); } ``` 5. You can use `DescribeMatcher<>` to describe another matcher. For example: ```cpp MATCHER_P(XAndYThat, matcher, "X that " + DescribeMatcher(matcher, negation) + (negation ? " or" : " and") + " Y that " + DescribeMatcher(matcher, negation)) { return ExplainMatchResult(matcher, arg.x(), result_listener) && ExplainMatchResult(matcher, arg.y(), result_listener); } ``` gperftools-gperftools-2.18/vendor/googletest/docs/reference/mocking.md000066400000000000000000000512171513545575200263440ustar00rootroot00000000000000# Mocking Reference This page lists the facilities provided by GoogleTest for creating and working with mock objects. To use them, add `#include `. ## Macros {#macros} GoogleTest defines the following macros for working with mocks. ### MOCK_METHOD {#MOCK_METHOD} `MOCK_METHOD(`*`return_type`*`,`*`method_name`*`, (`*`args...`*`));` \ `MOCK_METHOD(`*`return_type`*`,`*`method_name`*`, (`*`args...`*`), (`*`specs...`*`));` Defines a mock method *`method_name`* with arguments `(`*`args...`*`)` and return type *`return_type`* within a mock class. The parameters of `MOCK_METHOD` mirror the method declaration. The optional fourth parameter *`specs...`* is a comma-separated list of qualifiers. The following qualifiers are accepted: | Qualifier | Meaning | | -------------------------- | -------------------------------------------- | | `const` | Makes the mocked method a `const` method. Required if overriding a `const` method. | | `override` | Marks the method with `override`. Recommended if overriding a `virtual` method. | | `noexcept` | Marks the method with `noexcept`. Required if overriding a `noexcept` method. | | `Calltype(`*`calltype`*`)` | Sets the call type for the method, for example `Calltype(STDMETHODCALLTYPE)`. Useful on Windows. | | `ref(`*`qualifier`*`)` | Marks the method with the given reference qualifier, for example `ref(&)` or `ref(&&)`. Required if overriding a method that has a reference qualifier. | Note that commas in arguments prevent `MOCK_METHOD` from parsing the arguments correctly if they are not appropriately surrounded by parentheses. See the following example: ```cpp class MyMock { public: // The following 2 lines will not compile due to commas in the arguments: MOCK_METHOD(std::pair, GetPair, ()); // Error! MOCK_METHOD(bool, CheckMap, (std::map, bool)); // Error! // One solution - wrap arguments that contain commas in parentheses: MOCK_METHOD((std::pair), GetPair, ()); MOCK_METHOD(bool, CheckMap, ((std::map), bool)); // Another solution - use type aliases: using BoolAndInt = std::pair; MOCK_METHOD(BoolAndInt, GetPair, ()); using MapIntDouble = std::map; MOCK_METHOD(bool, CheckMap, (MapIntDouble, bool)); }; ``` `MOCK_METHOD` must be used in the `public:` section of a mock class definition, regardless of whether the method being mocked is `public`, `protected`, or `private` in the base class. ### EXPECT_CALL {#EXPECT_CALL} `EXPECT_CALL(`*`mock_object`*`,`*`method_name`*`(`*`matchers...`*`))` Creates an [expectation](../gmock_for_dummies.md#setting-expectations) that the method *`method_name`* of the object *`mock_object`* is called with arguments that match the given matchers *`matchers...`*. `EXPECT_CALL` must precede any code that exercises the mock object. The parameter *`matchers...`* is a comma-separated list of [matchers](../gmock_for_dummies.md#matchers-what-arguments-do-we-expect) that correspond to each argument of the method *`method_name`*. The expectation will apply only to calls of *`method_name`* whose arguments match all of the matchers. If `(`*`matchers...`*`)` is omitted, the expectation behaves as if each argument's matcher were a [wildcard matcher (`_`)](matchers.md#wildcard). See the [Matchers Reference](matchers.md) for a list of all built-in matchers. The following chainable clauses can be used to modify the expectation, and they must be used in the following order: ```cpp EXPECT_CALL(mock_object, method_name(matchers...)) .With(multi_argument_matcher) // Can be used at most once .Times(cardinality) // Can be used at most once .InSequence(sequences...) // Can be used any number of times .After(expectations...) // Can be used any number of times .WillOnce(action) // Can be used any number of times .WillRepeatedly(action) // Can be used at most once .RetiresOnSaturation(); // Can be used at most once ``` See details for each modifier clause below. #### With {#EXPECT_CALL.With} `.With(`*`multi_argument_matcher`*`)` Restricts the expectation to apply only to mock function calls whose arguments as a whole match the multi-argument matcher *`multi_argument_matcher`*. GoogleTest passes all of the arguments as one tuple into the matcher. The parameter *`multi_argument_matcher`* must thus be a matcher of type `Matcher>`, where `A1, ..., An` are the types of the function arguments. For example, the following code sets the expectation that `my_mock.SetPosition()` is called with any two arguments, the first argument being less than the second: ```cpp using ::testing::_; using ::testing::Lt; ... EXPECT_CALL(my_mock, SetPosition(_, _)) .With(Lt()); ``` GoogleTest provides some built-in matchers for 2-tuples, including the `Lt()` matcher above. See [Multi-argument Matchers](matchers.md#MultiArgMatchers). The `With` clause can be used at most once on an expectation and must be the first clause. #### Times {#EXPECT_CALL.Times} `.Times(`*`cardinality`*`)` Specifies how many times the mock function call is expected. The parameter *`cardinality`* represents the number of expected calls and can be one of the following, all defined in the `::testing` namespace: | Cardinality | Meaning | | ------------------- | --------------------------------------------------- | | `AnyNumber()` | The function can be called any number of times. | | `AtLeast(n)` | The function call is expected at least *n* times. | | `AtMost(n)` | The function call is expected at most *n* times. | | `Between(m, n)` | The function call is expected between *m* and *n* times, inclusive. | | `Exactly(n)` or `n` | The function call is expected exactly *n* times. If *n* is 0, the call should never happen. | If the `Times` clause is omitted, GoogleTest infers the cardinality as follows: * If neither [`WillOnce`](#EXPECT_CALL.WillOnce) nor [`WillRepeatedly`](#EXPECT_CALL.WillRepeatedly) are specified, the inferred cardinality is `Times(1)`. * If there are *n* `WillOnce` clauses and no `WillRepeatedly` clause, where *n* >= 1, the inferred cardinality is `Times(n)`. * If there are *n* `WillOnce` clauses and one `WillRepeatedly` clause, where *n* >= 0, the inferred cardinality is `Times(AtLeast(n))`. The `Times` clause can be used at most once on an expectation. #### InSequence {#EXPECT_CALL.InSequence} `.InSequence(`*`sequences...`*`)` Specifies that the mock function call is expected in a certain sequence. The parameter *`sequences...`* is any number of [`Sequence`](#Sequence) objects. Expected calls assigned to the same sequence are expected to occur in the order the expectations are declared. For example, the following code sets the expectation that the `Reset()` method of `my_mock` is called before both `GetSize()` and `Describe()`, and `GetSize()` and `Describe()` can occur in any order relative to each other: ```cpp using ::testing::Sequence; Sequence s1, s2; ... EXPECT_CALL(my_mock, Reset()) .InSequence(s1, s2); EXPECT_CALL(my_mock, GetSize()) .InSequence(s1); EXPECT_CALL(my_mock, Describe()) .InSequence(s2); ``` The `InSequence` clause can be used any number of times on an expectation. See also the [`InSequence` class](#InSequence). #### After {#EXPECT_CALL.After} `.After(`*`expectations...`*`)` Specifies that the mock function call is expected to occur after one or more other calls. The parameter *`expectations...`* can be up to five [`Expectation`](#Expectation) or [`ExpectationSet`](#ExpectationSet) objects. The mock function call is expected to occur after all of the given expectations. For example, the following code sets the expectation that the `Describe()` method of `my_mock` is called only after both `InitX()` and `InitY()` have been called. ```cpp using ::testing::Expectation; ... Expectation init_x = EXPECT_CALL(my_mock, InitX()); Expectation init_y = EXPECT_CALL(my_mock, InitY()); EXPECT_CALL(my_mock, Describe()) .After(init_x, init_y); ``` The `ExpectationSet` object is helpful when the number of prerequisites for an expectation is large or variable, for example: ```cpp using ::testing::ExpectationSet; ... ExpectationSet all_inits; // Collect all expectations of InitElement() calls for (int i = 0; i < element_count; i++) { all_inits += EXPECT_CALL(my_mock, InitElement(i)); } EXPECT_CALL(my_mock, Describe()) .After(all_inits); // Expect Describe() call after all InitElement() calls ``` The `After` clause can be used any number of times on an expectation. #### WillOnce {#EXPECT_CALL.WillOnce} `.WillOnce(`*`action`*`)` Specifies the mock function's actual behavior when invoked, for a single matching function call. The parameter *`action`* represents the [action](../gmock_for_dummies.md#actions-what-should-it-do) that the function call will perform. See the [Actions Reference](actions.md) for a list of built-in actions. The use of `WillOnce` implicitly sets a cardinality on the expectation when `Times` is not specified. See [`Times`](#EXPECT_CALL.Times). Each matching function call will perform the next action in the order declared. For example, the following code specifies that `my_mock.GetNumber()` is expected to be called exactly 3 times and will return `1`, `2`, and `3` respectively on the first, second, and third calls: ```cpp using ::testing::Return; ... EXPECT_CALL(my_mock, GetNumber()) .WillOnce(Return(1)) .WillOnce(Return(2)) .WillOnce(Return(3)); ``` The `WillOnce` clause can be used any number of times on an expectation. Unlike `WillRepeatedly`, the action fed to each `WillOnce` call will be called at most once, so may be a move-only type and/or have an `&&`-qualified call operator. #### WillRepeatedly {#EXPECT_CALL.WillRepeatedly} `.WillRepeatedly(`*`action`*`)` Specifies the mock function's actual behavior when invoked, for all subsequent matching function calls. Takes effect after the actions specified in the [`WillOnce`](#EXPECT_CALL.WillOnce) clauses, if any, have been performed. The parameter *`action`* represents the [action](../gmock_for_dummies.md#actions-what-should-it-do) that the function call will perform. See the [Actions Reference](actions.md) for a list of built-in actions. The use of `WillRepeatedly` implicitly sets a cardinality on the expectation when `Times` is not specified. See [`Times`](#EXPECT_CALL.Times). If any `WillOnce` clauses have been specified, matching function calls will perform those actions before the action specified by `WillRepeatedly`. See the following example: ```cpp using ::testing::Return; ... EXPECT_CALL(my_mock, GetName()) .WillRepeatedly(Return("John Doe")); // Return "John Doe" on all calls EXPECT_CALL(my_mock, GetNumber()) .WillOnce(Return(42)) // Return 42 on the first call .WillRepeatedly(Return(7)); // Return 7 on all subsequent calls ``` The `WillRepeatedly` clause can be used at most once on an expectation. #### RetiresOnSaturation {#EXPECT_CALL.RetiresOnSaturation} `.RetiresOnSaturation()` Indicates that the expectation will no longer be active after the expected number of matching function calls has been reached. The `RetiresOnSaturation` clause is only meaningful for expectations with an upper-bounded cardinality. The expectation will *retire* (no longer match any function calls) after it has been *saturated* (the upper bound has been reached). See the following example: ```cpp using ::testing::_; using ::testing::AnyNumber; ... EXPECT_CALL(my_mock, SetNumber(_)) // Expectation 1 .Times(AnyNumber()); EXPECT_CALL(my_mock, SetNumber(7)) // Expectation 2 .Times(2) .RetiresOnSaturation(); ``` In the above example, the first two calls to `my_mock.SetNumber(7)` match expectation 2, which then becomes inactive and no longer matches any calls. A third call to `my_mock.SetNumber(7)` would then match expectation 1. Without `RetiresOnSaturation()` on expectation 2, a third call to `my_mock.SetNumber(7)` would match expectation 2 again, producing a failure since the limit of 2 calls was exceeded. The `RetiresOnSaturation` clause can be used at most once on an expectation and must be the last clause. ### ON_CALL {#ON_CALL} `ON_CALL(`*`mock_object`*`,`*`method_name`*`(`*`matchers...`*`))` Defines what happens when the method *`method_name`* of the object *`mock_object`* is called with arguments that match the given matchers *`matchers...`*. Requires a modifier clause to specify the method's behavior. *Does not* set any expectations that the method will be called. The parameter *`matchers...`* is a comma-separated list of [matchers](../gmock_for_dummies.md#matchers-what-arguments-do-we-expect) that correspond to each argument of the method *`method_name`*. The `ON_CALL` specification will apply only to calls of *`method_name`* whose arguments match all of the matchers. If `(`*`matchers...`*`)` is omitted, the behavior is as if each argument's matcher were a [wildcard matcher (`_`)](matchers.md#wildcard). See the [Matchers Reference](matchers.md) for a list of all built-in matchers. The following chainable clauses can be used to set the method's behavior, and they must be used in the following order: ```cpp ON_CALL(mock_object, method_name(matchers...)) .With(multi_argument_matcher) // Can be used at most once .WillByDefault(action); // Required ``` See details for each modifier clause below. #### With {#ON_CALL.With} `.With(`*`multi_argument_matcher`*`)` Restricts the specification to only mock function calls whose arguments as a whole match the multi-argument matcher *`multi_argument_matcher`*. GoogleTest passes all of the arguments as one tuple into the matcher. The parameter *`multi_argument_matcher`* must thus be a matcher of type `Matcher>`, where `A1, ..., An` are the types of the function arguments. For example, the following code sets the default behavior when `my_mock.SetPosition()` is called with any two arguments, the first argument being less than the second: ```cpp using ::testing::_; using ::testing::Lt; using ::testing::Return; ... ON_CALL(my_mock, SetPosition(_, _)) .With(Lt()) .WillByDefault(Return(true)); ``` GoogleTest provides some built-in matchers for 2-tuples, including the `Lt()` matcher above. See [Multi-argument Matchers](matchers.md#MultiArgMatchers). The `With` clause can be used at most once with each `ON_CALL` statement. #### WillByDefault {#ON_CALL.WillByDefault} `.WillByDefault(`*`action`*`)` Specifies the default behavior of a matching mock function call. The parameter *`action`* represents the [action](../gmock_for_dummies.md#actions-what-should-it-do) that the function call will perform. See the [Actions Reference](actions.md) for a list of built-in actions. For example, the following code specifies that by default, a call to `my_mock.Greet()` will return `"hello"`: ```cpp using ::testing::Return; ... ON_CALL(my_mock, Greet()) .WillByDefault(Return("hello")); ``` The action specified by `WillByDefault` is superseded by the actions specified on a matching `EXPECT_CALL` statement, if any. See the [`WillOnce`](#EXPECT_CALL.WillOnce) and [`WillRepeatedly`](#EXPECT_CALL.WillRepeatedly) clauses of `EXPECT_CALL`. The `WillByDefault` clause must be used exactly once with each `ON_CALL` statement. ## Classes {#classes} GoogleTest defines the following classes for working with mocks. ### DefaultValue {#DefaultValue} `::testing::DefaultValue` Allows a user to specify the default value for a type `T` that is both copyable and publicly destructible (i.e. anything that can be used as a function return type). For mock functions with a return type of `T`, this default value is returned from function calls that do not specify an action. Provides the static methods `Set()`, `SetFactory()`, and `Clear()` to manage the default value: ```cpp // Sets the default value to be returned. T must be copy constructible. DefaultValue::Set(value); // Sets a factory. Will be invoked on demand. T must be move constructible. T MakeT(); DefaultValue::SetFactory(&MakeT); // Unsets the default value. DefaultValue::Clear(); ``` ### NiceMock {#NiceMock} `::testing::NiceMock` Represents a mock object that suppresses warnings on [uninteresting calls](../gmock_cook_book.md#uninteresting-vs-unexpected). The template parameter `T` is any mock class, except for another `NiceMock`, `NaggyMock`, or `StrictMock`. Usage of `NiceMock` is analogous to usage of `T`. `NiceMock` is a subclass of `T`, so it can be used wherever an object of type `T` is accepted. In addition, `NiceMock` can be constructed with any arguments that a constructor of `T` accepts. For example, the following code suppresses warnings on the mock `my_mock` of type `MockClass` if a method other than `DoSomething()` is called: ```cpp using ::testing::NiceMock; ... NiceMock my_mock("some", "args"); EXPECT_CALL(my_mock, DoSomething()); ... code that uses my_mock ... ``` `NiceMock` only works for mock methods defined using the `MOCK_METHOD` macro directly in the definition of class `T`. If a mock method is defined in a base class of `T`, a warning might still be generated. `NiceMock` might not work correctly if the destructor of `T` is not virtual. ### NaggyMock {#NaggyMock} `::testing::NaggyMock` Represents a mock object that generates warnings on [uninteresting calls](../gmock_cook_book.md#uninteresting-vs-unexpected). The template parameter `T` is any mock class, except for another `NiceMock`, `NaggyMock`, or `StrictMock`. Usage of `NaggyMock` is analogous to usage of `T`. `NaggyMock` is a subclass of `T`, so it can be used wherever an object of type `T` is accepted. In addition, `NaggyMock` can be constructed with any arguments that a constructor of `T` accepts. For example, the following code generates warnings on the mock `my_mock` of type `MockClass` if a method other than `DoSomething()` is called: ```cpp using ::testing::NaggyMock; ... NaggyMock my_mock("some", "args"); EXPECT_CALL(my_mock, DoSomething()); ... code that uses my_mock ... ``` Mock objects of type `T` by default behave the same way as `NaggyMock`. ### StrictMock {#StrictMock} `::testing::StrictMock` Represents a mock object that generates test failures on [uninteresting calls](../gmock_cook_book.md#uninteresting-vs-unexpected). The template parameter `T` is any mock class, except for another `NiceMock`, `NaggyMock`, or `StrictMock`. Usage of `StrictMock` is analogous to usage of `T`. `StrictMock` is a subclass of `T`, so it can be used wherever an object of type `T` is accepted. In addition, `StrictMock` can be constructed with any arguments that a constructor of `T` accepts. For example, the following code generates a test failure on the mock `my_mock` of type `MockClass` if a method other than `DoSomething()` is called: ```cpp using ::testing::StrictMock; ... StrictMock my_mock("some", "args"); EXPECT_CALL(my_mock, DoSomething()); ... code that uses my_mock ... ``` `StrictMock` only works for mock methods defined using the `MOCK_METHOD` macro directly in the definition of class `T`. If a mock method is defined in a base class of `T`, a failure might not be generated. `StrictMock` might not work correctly if the destructor of `T` is not virtual. ### Sequence {#Sequence} `::testing::Sequence` Represents a chronological sequence of expectations. See the [`InSequence`](#EXPECT_CALL.InSequence) clause of `EXPECT_CALL` for usage. ### InSequence {#InSequence} `::testing::InSequence` An object of this type causes all expectations encountered in its scope to be put in an anonymous sequence. This allows more convenient expression of multiple expectations in a single sequence: ```cpp using ::testing::InSequence; { InSequence seq; // The following are expected to occur in the order declared. EXPECT_CALL(...); EXPECT_CALL(...); ... EXPECT_CALL(...); } ``` The name of the `InSequence` object does not matter. ### Expectation {#Expectation} `::testing::Expectation` Represents a mock function call expectation as created by [`EXPECT_CALL`](#EXPECT_CALL): ```cpp using ::testing::Expectation; Expectation my_expectation = EXPECT_CALL(...); ``` Useful for specifying sequences of expectations; see the [`After`](#EXPECT_CALL.After) clause of `EXPECT_CALL`. ### ExpectationSet {#ExpectationSet} `::testing::ExpectationSet` Represents a set of mock function call expectations. Use the `+=` operator to add [`Expectation`](#Expectation) objects to the set: ```cpp using ::testing::ExpectationSet; ExpectationSet my_expectations; my_expectations += EXPECT_CALL(...); ``` Useful for specifying sequences of expectations; see the [`After`](#EXPECT_CALL.After) clause of `EXPECT_CALL`. gperftools-gperftools-2.18/vendor/googletest/docs/reference/testing.md000066400000000000000000001376361513545575200264040ustar00rootroot00000000000000# Testing Reference This page lists the facilities provided by GoogleTest for writing test programs. To use them, add `#include `. ## Macros GoogleTest defines the following macros for writing tests. ### TEST {#TEST}
TEST(TestSuiteName, TestName) {
  ... statements ...
}
Defines an individual test named *`TestName`* in the test suite *`TestSuiteName`*, consisting of the given statements. Both arguments *`TestSuiteName`* and *`TestName`* must be valid C++ identifiers and must not contain underscores (`_`). Tests in different test suites can have the same individual name. The statements within the test body can be any code under test. [Assertions](assertions.md) used within the test body determine the outcome of the test. ### TEST_F {#TEST_F}
TEST_F(TestFixtureName, TestName) {
  ... statements ...
}
Defines an individual test named *`TestName`* that uses the test fixture class *`TestFixtureName`*. The test suite name is *`TestFixtureName`*. Both arguments *`TestFixtureName`* and *`TestName`* must be valid C++ identifiers and must not contain underscores (`_`). *`TestFixtureName`* must be the name of a test fixture class—see [Test Fixtures](../primer.md#same-data-multiple-tests). The statements within the test body can be any code under test. [Assertions](assertions.md) used within the test body determine the outcome of the test. ### TEST_P {#TEST_P}
TEST_P(TestFixtureName, TestName) {
  ... statements ...
}
Defines an individual value-parameterized test named *`TestName`* that uses the test fixture class *`TestFixtureName`*. The test suite name is *`TestFixtureName`*. Both arguments *`TestFixtureName`* and *`TestName`* must be valid C++ identifiers and must not contain underscores (`_`). *`TestFixtureName`* must be the name of a value-parameterized test fixture class—see [Value-Parameterized Tests](../advanced.md#value-parameterized-tests). The statements within the test body can be any code under test. Within the test body, the test parameter can be accessed with the `GetParam()` function (see [`WithParamInterface`](#WithParamInterface)). For example: ```cpp TEST_P(MyTestSuite, DoesSomething) { ... EXPECT_TRUE(DoSomething(GetParam())); ... } ``` [Assertions](assertions.md) used within the test body determine the outcome of the test. See also [`INSTANTIATE_TEST_SUITE_P`](#INSTANTIATE_TEST_SUITE_P). ### INSTANTIATE_TEST_SUITE_P {#INSTANTIATE_TEST_SUITE_P} `INSTANTIATE_TEST_SUITE_P(`*`InstantiationName`*`,`*`TestSuiteName`*`,`*`param_generator`*`)` \ `INSTANTIATE_TEST_SUITE_P(`*`InstantiationName`*`,`*`TestSuiteName`*`,`*`param_generator`*`,`*`name_generator`*`)` Instantiates the value-parameterized test suite *`TestSuiteName`* (defined with [`TEST_P`](#TEST_P)). The argument *`InstantiationName`* is a unique name for the instantiation of the test suite, to distinguish between multiple instantiations. In test output, the instantiation name is added as a prefix to the test suite name *`TestSuiteName`*. If *`InstantiationName`* is empty (`INSTANTIATE_TEST_SUITE_P(, ...)`), no prefix is added. The argument *`param_generator`* is one of the following GoogleTest-provided functions that generate the test parameters, all defined in the `::testing` namespace: | Parameter Generator | Behavior | | ------------------- | ---------------------------------------------------- | | `Range(begin, end [, step])` | Yields values `{begin, begin+step, begin+step+step, ...}`. The values do not include `end`. `step` defaults to 1. | | `Values(v1, v2, ..., vN)` | Yields values `{v1, v2, ..., vN}`. | | `ValuesIn(container)` or `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. | | `Bool()` | Yields sequence `{false, true}`. | | `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. | | `ConvertGenerator(g)` or `ConvertGenerator(g, func)` | Yields values generated by generator `g`, `static_cast` from `T`. (Note: `T` might not be what you expect. See [*Using ConvertGenerator*](#using-convertgenerator) below.) The second overload uses `func` to perform the conversion. | The optional last argument *`name_generator`* is a function or functor that generates custom test name suffixes based on the test parameters. The function must accept an argument of type [`TestParamInfo`](#TestParamInfo) and return a `std::string`. The test name suffix can only contain alphanumeric characters and underscores. GoogleTest provides [`PrintToStringParamName`](#PrintToStringParamName), or a custom function can be used for more control: ```cpp INSTANTIATE_TEST_SUITE_P( MyInstantiation, MyTestSuite, testing::Values(...), [](const testing::TestParamInfo& info) { // Can use info.param here to generate the test suffix std::string name = ... return name; }); ``` For more information, see [Value-Parameterized Tests](../advanced.md#value-parameterized-tests). See also [`GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST`](#GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST). ###### Using `ConvertGenerator` The functions listed in the table above appear to return generators that create values of the desired types, but this is not generally the case. Rather, they typically return factory objects that convert to the the desired generators. This affords some flexibility in allowing you to specify values of types that are different from, yet implicitly convertible to, the actual parameter type required by your fixture class. For example, you can do the following with a fixture that requires an `int` parameter: ```cpp INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite, testing::Values(1, 1.2)); // Yes, Values() supports heterogeneous argument types. ``` It might seem obvious that `1.2` — a `double` — will be converted to an `int` but in actuality it requires some template gymnastics involving the indirection described in the previous paragraph. What if your parameter type is not implicitly convertible from the generated type but is *explicitly* convertible? There will be no automatic conversion, but you can force it by applying `ConvertGenerator`. The compiler can automatically deduce the target type (your fixture's parameter type), but because of the aforementioned indirection it cannot decide what the generated type should be. You need to tell it, by providing the type `T` explicitly. Thus `T` should not be your fixture's parameter type, but rather an intermediate type that is supported by the factory object, and which can be `static_cast` to the fixture's parameter type: ```cpp // The fixture's parameter type. class MyParam { public: // Explicit converting ctor. explicit MyParam(const std::tuple& t); ... }; INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite, ConvertGenerator>(Combine(Values(0.1, 1.2), Bool()))); ``` In this example `Combine` supports the generation of `std::tuple>` objects (even though the provided values for the first tuple element are `double`s) and those `tuple`s get converted into `MyParam` objects by virtue of the call to `ConvertGenerator`. For parameter types that are not convertible from the generated types you can provide a callable that does the conversion. The callable accepts an object of the generated type and returns an object of the fixture's parameter type. The generated type can often be deduced by the compiler from the callable's call signature so you do not usually need specify it explicitly (but see a caveat below). ```cpp // The fixture's parameter type. class MyParam { public: MyParam(int, bool); ... }; INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite, ConvertGenerator(Combine(Values(1, 1.2), Bool()), [](const std::tuple& t){ const auto [i, b] = t; return MyParam(i, b); })); ``` The callable may be anything that can be used to initialize a `std::function` with the appropriate call signature. Note the callable's return object gets `static_cast` to the fixture's parameter type, so it does not have to be of that exact type, only convertible to it. **Caveat:** Consider the following example. ```cpp INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite, ConvertGenerator(Values(std::string("s")), [](std::string_view s) { ... })); ``` The `string` argument gets copied into the factory object returned by `Values`. Then, because the generated type deduced from the lambda is `string_view`, the factory object spawns a generator that holds a `string_view` referencing that `string`. Unfortunately, by the time this generator gets invoked, the factory object is gone and the `string_view` is dangling. To overcome this problem you can specify the generated type explicitly: `ConvertGenerator(Values(std::string("s")), [](std::string_view s) { ... })`. Alternatively, you can change the lambda's signature to take a `std::string` or a `const std::string&` (the latter will not leave you with a dangling reference because the type deduction strips off the reference and the `const`). ### TYPED_TEST_SUITE {#TYPED_TEST_SUITE} `TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)` `TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`,`*`NameGenerator`*`)` Defines a typed test suite based on the test fixture *`TestFixtureName`*. The test suite name is *`TestFixtureName`*. The argument *`TestFixtureName`* is a fixture class template, parameterized by a type, for example: ```cpp template class MyFixture : public testing::Test { public: ... using List = std::list; static T shared_; T value_; }; ``` The argument *`Types`* is a [`Types`](#Types) object representing the list of types to run the tests on, for example: ```cpp using MyTypes = ::testing::Types; TYPED_TEST_SUITE(MyFixture, MyTypes); ``` The type alias (`using` or `typedef`) is necessary for the `TYPED_TEST_SUITE` macro to parse correctly. The optional third argument *`NameGenerator`* allows specifying a class that exposes a templated static function `GetName(int)`. For example: ```cpp class NameGenerator { public: template static std::string GetName(int) { if constexpr (std::is_same_v) return "char"; if constexpr (std::is_same_v) return "int"; if constexpr (std::is_same_v) return "unsignedInt"; } }; TYPED_TEST_SUITE(MyFixture, MyTypes, NameGenerator); ``` See also [`TYPED_TEST`](#TYPED_TEST) and [Typed Tests](../advanced.md#typed-tests) for more information. ### TYPED_TEST {#TYPED_TEST}
TYPED_TEST(TestSuiteName, TestName) {
  ... statements ...
}
Defines an individual typed test named *`TestName`* in the typed test suite *`TestSuiteName`*. The test suite must be defined with [`TYPED_TEST_SUITE`](#TYPED_TEST_SUITE). Within the test body, the special name `TypeParam` refers to the type parameter, and `TestFixture` refers to the fixture class. See the following example: ```cpp TYPED_TEST(MyFixture, Example) { // Inside a test, refer to the special name TypeParam to get the type // parameter. Since we are inside a derived class template, C++ requires // us to visit the members of MyFixture via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the 'TestFixture::' // prefix. n += TestFixture::shared_; // To refer to typedefs in the fixture, add the 'typename TestFixture::' // prefix. The 'typename' is required to satisfy the compiler. typename TestFixture::List values; values.push_back(n); ... } ``` For more information, see [Typed Tests](../advanced.md#typed-tests). ### TYPED_TEST_SUITE_P {#TYPED_TEST_SUITE_P} `TYPED_TEST_SUITE_P(`*`TestFixtureName`*`)` Defines a type-parameterized test suite based on the test fixture *`TestFixtureName`*. The test suite name is *`TestFixtureName`*. The argument *`TestFixtureName`* is a fixture class template, parameterized by a type. See [`TYPED_TEST_SUITE`](#TYPED_TEST_SUITE) for an example. See also [`TYPED_TEST_P`](#TYPED_TEST_P) and [Type-Parameterized Tests](../advanced.md#type-parameterized-tests) for more information. ### TYPED_TEST_P {#TYPED_TEST_P}
TYPED_TEST_P(TestSuiteName, TestName) {
  ... statements ...
}
Defines an individual type-parameterized test named *`TestName`* in the type-parameterized test suite *`TestSuiteName`*. The test suite must be defined with [`TYPED_TEST_SUITE_P`](#TYPED_TEST_SUITE_P). Within the test body, the special name `TypeParam` refers to the type parameter, and `TestFixture` refers to the fixture class. See [`TYPED_TEST`](#TYPED_TEST) for an example. See also [`REGISTER_TYPED_TEST_SUITE_P`](#REGISTER_TYPED_TEST_SUITE_P) and [Type-Parameterized Tests](../advanced.md#type-parameterized-tests) for more information. ### REGISTER_TYPED_TEST_SUITE_P {#REGISTER_TYPED_TEST_SUITE_P} `REGISTER_TYPED_TEST_SUITE_P(`*`TestSuiteName`*`,`*`TestNames...`*`)` Registers the type-parameterized tests *`TestNames...`* of the test suite *`TestSuiteName`*. The test suite and tests must be defined with [`TYPED_TEST_SUITE_P`](#TYPED_TEST_SUITE_P) and [`TYPED_TEST_P`](#TYPED_TEST_P). For example: ```cpp // Define the test suite and tests. TYPED_TEST_SUITE_P(MyFixture); TYPED_TEST_P(MyFixture, HasPropertyA) { ... } TYPED_TEST_P(MyFixture, HasPropertyB) { ... } // Register the tests in the test suite. REGISTER_TYPED_TEST_SUITE_P(MyFixture, HasPropertyA, HasPropertyB); ``` See also [`INSTANTIATE_TYPED_TEST_SUITE_P`](#INSTANTIATE_TYPED_TEST_SUITE_P) and [Type-Parameterized Tests](../advanced.md#type-parameterized-tests) for more information. ### INSTANTIATE_TYPED_TEST_SUITE_P {#INSTANTIATE_TYPED_TEST_SUITE_P} `INSTANTIATE_TYPED_TEST_SUITE_P(`*`InstantiationName`*`,`*`TestSuiteName`*`,`*`Types`*`)` Instantiates the type-parameterized test suite *`TestSuiteName`*. The test suite must be registered with [`REGISTER_TYPED_TEST_SUITE_P`](#REGISTER_TYPED_TEST_SUITE_P). The argument *`InstantiationName`* is a unique name for the instantiation of the test suite, to distinguish between multiple instantiations. In test output, the instantiation name is added as a prefix to the test suite name *`TestSuiteName`*. If *`InstantiationName`* is empty (`INSTANTIATE_TYPED_TEST_SUITE_P(, ...)`), no prefix is added. The argument *`Types`* is a [`Types`](#Types) object representing the list of types to run the tests on, for example: ```cpp using MyTypes = ::testing::Types; INSTANTIATE_TYPED_TEST_SUITE_P(MyInstantiation, MyFixture, MyTypes); ``` The type alias (`using` or `typedef`) is necessary for the `INSTANTIATE_TYPED_TEST_SUITE_P` macro to parse correctly. For more information, see [Type-Parameterized Tests](../advanced.md#type-parameterized-tests). ### FRIEND_TEST {#FRIEND_TEST} `FRIEND_TEST(`*`TestSuiteName`*`,`*`TestName`*`)` Within a class body, declares an individual test as a friend of the class, enabling the test to access private class members. If the class is defined in a namespace, then in order to be friends of the class, test fixtures and tests must be defined in the exact same namespace, without inline or anonymous namespaces. For example, if the class definition looks like the following: ```cpp namespace my_namespace { class MyClass { friend class MyClassTest; FRIEND_TEST(MyClassTest, HasPropertyA); FRIEND_TEST(MyClassTest, HasPropertyB); ... definition of class MyClass ... }; } // namespace my_namespace ``` Then the test code should look like: ```cpp namespace my_namespace { class MyClassTest : public testing::Test { ... }; TEST_F(MyClassTest, HasPropertyA) { ... } TEST_F(MyClassTest, HasPropertyB) { ... } } // namespace my_namespace ``` See [Testing Private Code](../advanced.md#testing-private-code) for more information. ### SCOPED_TRACE {#SCOPED_TRACE} `SCOPED_TRACE(`*`message`*`)` Causes the current file name, line number, and the given message *`message`* to be added to the failure message for each assertion failure that occurs in the scope. For more information, see [Adding Traces to Assertions](../advanced.md#adding-traces-to-assertions). See also the [`ScopedTrace` class](#ScopedTrace). ### GTEST_SKIP {#GTEST_SKIP} `GTEST_SKIP()` Prevents further test execution at runtime. Can be used in individual test cases or in the `SetUp()` methods of test environments or test fixtures (classes derived from the [`Environment`](#Environment) or [`Test`](#Test) classes). If used in a global test environment `SetUp()` method, it skips all tests in the test program. If used in a test fixture `SetUp()` method, it skips all tests in the corresponding test suite. Similar to assertions, `GTEST_SKIP` allows streaming a custom message into it. See [Skipping Test Execution](../advanced.md#skipping-test-execution) for more information. ### GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST {#GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST} `GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(`*`TestSuiteName`*`)` Allows the value-parameterized test suite *`TestSuiteName`* to be uninstantiated. By default, every [`TEST_P`](#TEST_P) call without a corresponding [`INSTANTIATE_TEST_SUITE_P`](#INSTANTIATE_TEST_SUITE_P) call causes a failing test in the test suite `GoogleTestVerification`. `GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST` suppresses this failure for the given test suite. ## Classes and types GoogleTest defines the following classes and types to help with writing tests. ### AssertionResult {#AssertionResult} `testing::AssertionResult` A class for indicating whether an assertion was successful. When the assertion wasn't successful, the `AssertionResult` object stores a non-empty failure message that can be retrieved with the object's `message()` method. To create an instance of this class, use one of the factory functions [`AssertionSuccess()`](#AssertionSuccess) or [`AssertionFailure()`](#AssertionFailure). ### AssertionException {#AssertionException} `testing::AssertionException` Exception which can be thrown from [`TestEventListener::OnTestPartResult`](#TestEventListener::OnTestPartResult). ### EmptyTestEventListener {#EmptyTestEventListener} `testing::EmptyTestEventListener` Provides an empty implementation of all methods in the [`TestEventListener`](#TestEventListener) interface, such that a subclass only needs to override the methods it cares about. ### Environment {#Environment} `testing::Environment` Represents a global test environment. See [Global Set-Up and Tear-Down](../advanced.md#global-set-up-and-tear-down). #### Protected Methods {#Environment-protected} ##### SetUp {#Environment::SetUp} `virtual void Environment::SetUp()` Override this to define how to set up the environment. ##### TearDown {#Environment::TearDown} `virtual void Environment::TearDown()` Override this to define how to tear down the environment. ### ScopedTrace {#ScopedTrace} `testing::ScopedTrace` An instance of this class causes a trace to be included in every test failure message generated by code in the scope of the lifetime of the `ScopedTrace` instance. The effect is undone with the destruction of the instance. The `ScopedTrace` constructor has the following form: ```cpp template ScopedTrace(const char* file, int line, const T& message) ``` Example usage: ```cpp testing::ScopedTrace trace("file.cc", 123, "message"); ``` The resulting trace includes the given source file path and line number, and the given message. The `message` argument can be anything streamable to `std::ostream`. See also [`SCOPED_TRACE`](#SCOPED_TRACE). ### Test {#Test} `testing::Test` The abstract class that all tests inherit from. `Test` is not copyable. #### Public Methods {#Test-public} ##### SetUpTestSuite {#Test::SetUpTestSuite} `static void Test::SetUpTestSuite()` Performs shared setup for all tests in the test suite. GoogleTest calls `SetUpTestSuite()` before running the first test in the test suite. ##### TearDownTestSuite {#Test::TearDownTestSuite} `static void Test::TearDownTestSuite()` Performs shared teardown for all tests in the test suite. GoogleTest calls `TearDownTestSuite()` after running the last test in the test suite. ##### HasFatalFailure {#Test::HasFatalFailure} `static bool Test::HasFatalFailure()` Returns true if and only if the current test has a fatal failure. ##### HasNonfatalFailure {#Test::HasNonfatalFailure} `static bool Test::HasNonfatalFailure()` Returns true if and only if the current test has a nonfatal failure. ##### HasFailure {#Test::HasFailure} `static bool Test::HasFailure()` Returns true if and only if the current test has any failure, either fatal or nonfatal. ##### IsSkipped {#Test::IsSkipped} `static bool Test::IsSkipped()` Returns true if and only if the current test was skipped. ##### RecordProperty {#Test::RecordProperty} `static void Test::RecordProperty(const std::string& key, const std::string& value)` \ `static void Test::RecordProperty(const std::string& key, int value)` Logs a property for the current test, test suite, or entire invocation of the test program. Only the last value for a given key is logged. The key must be a valid XML attribute name, and cannot conflict with the ones already used by GoogleTest (`name`, `file`, `line`, `status`, `time`, `classname`, `type_param`, and `value_param`). `RecordProperty` is `public static` so it can be called from utility functions that are not members of the test fixture. Calls to `RecordProperty` made during the lifespan of the test (from the moment its constructor starts to the moment its destructor finishes) are output in XML as attributes of the `` element. Properties recorded from a fixture's `SetUpTestSuite` or `TearDownTestSuite` methods are logged as attributes of the corresponding `` element. Calls to `RecordProperty` made in the global context (before or after invocation of `RUN_ALL_TESTS` or from the `SetUp`/`TearDown` methods of registered `Environment` objects) are output as attributes of the `` element. #### Protected Methods {#Test-protected} ##### SetUp {#Test::SetUp} `virtual void Test::SetUp()` Override this to perform test fixture setup. GoogleTest calls `SetUp()` before running each individual test. ##### TearDown {#Test::TearDown} `virtual void Test::TearDown()` Override this to perform test fixture teardown. GoogleTest calls `TearDown()` after running each individual test. ### TestWithParam {#TestWithParam} `testing::TestWithParam` A convenience class which inherits from both [`Test`](#Test) and [`WithParamInterface`](#WithParamInterface). ### TestSuite {#TestSuite} Represents a test suite. `TestSuite` is not copyable. #### Public Methods {#TestSuite-public} ##### name {#TestSuite::name} `const char* TestSuite::name() const` Gets the name of the test suite. ##### type_param {#TestSuite::type_param} `const char* TestSuite::type_param() const` Returns the name of the parameter type, or `NULL` if this is not a typed or type-parameterized test suite. See [Typed Tests](../advanced.md#typed-tests) and [Type-Parameterized Tests](../advanced.md#type-parameterized-tests). ##### should_run {#TestSuite::should_run} `bool TestSuite::should_run() const` Returns true if any test in this test suite should run. ##### successful_test_count {#TestSuite::successful_test_count} `int TestSuite::successful_test_count() const` Gets the number of successful tests in this test suite. ##### skipped_test_count {#TestSuite::skipped_test_count} `int TestSuite::skipped_test_count() const` Gets the number of skipped tests in this test suite. ##### failed_test_count {#TestSuite::failed_test_count} `int TestSuite::failed_test_count() const` Gets the number of failed tests in this test suite. ##### reportable_disabled_test_count {#TestSuite::reportable_disabled_test_count} `int TestSuite::reportable_disabled_test_count() const` Gets the number of disabled tests that will be reported in the XML report. ##### disabled_test_count {#TestSuite::disabled_test_count} `int TestSuite::disabled_test_count() const` Gets the number of disabled tests in this test suite. ##### reportable_test_count {#TestSuite::reportable_test_count} `int TestSuite::reportable_test_count() const` Gets the number of tests to be printed in the XML report. ##### test_to_run_count {#TestSuite::test_to_run_count} `int TestSuite::test_to_run_count() const` Get the number of tests in this test suite that should run. ##### total_test_count {#TestSuite::total_test_count} `int TestSuite::total_test_count() const` Gets the number of all tests in this test suite. ##### Passed {#TestSuite::Passed} `bool TestSuite::Passed() const` Returns true if and only if the test suite passed. ##### Failed {#TestSuite::Failed} `bool TestSuite::Failed() const` Returns true if and only if the test suite failed. ##### elapsed_time {#TestSuite::elapsed_time} `TimeInMillis TestSuite::elapsed_time() const` Returns the elapsed time, in milliseconds. ##### start_timestamp {#TestSuite::start_timestamp} `TimeInMillis TestSuite::start_timestamp() const` Gets the time of the test suite start, in ms from the start of the UNIX epoch. ##### GetTestInfo {#TestSuite::GetTestInfo} `const TestInfo* TestSuite::GetTestInfo(int i) const` Returns the [`TestInfo`](#TestInfo) for the `i`-th test among all the tests. `i` can range from 0 to `total_test_count() - 1`. If `i` is not in that range, returns `NULL`. ##### ad_hoc_test_result {#TestSuite::ad_hoc_test_result} `const TestResult& TestSuite::ad_hoc_test_result() const` Returns the [`TestResult`](#TestResult) that holds test properties recorded during execution of `SetUpTestSuite` and `TearDownTestSuite`. ### TestInfo {#TestInfo} `testing::TestInfo` Stores information about a test. #### Public Methods {#TestInfo-public} ##### test_suite_name {#TestInfo::test_suite_name} `const char* TestInfo::test_suite_name() const` Returns the test suite name. ##### name {#TestInfo::name} `const char* TestInfo::name() const` Returns the test name. ##### type_param {#TestInfo::type_param} `const char* TestInfo::type_param() const` Returns the name of the parameter type, or `NULL` if this is not a typed or type-parameterized test. See [Typed Tests](../advanced.md#typed-tests) and [Type-Parameterized Tests](../advanced.md#type-parameterized-tests). ##### value_param {#TestInfo::value_param} `const char* TestInfo::value_param() const` Returns the text representation of the value parameter, or `NULL` if this is not a value-parameterized test. See [Value-Parameterized Tests](../advanced.md#value-parameterized-tests). ##### file {#TestInfo::file} `const char* TestInfo::file() const` Returns the file name where this test is defined. ##### line {#TestInfo::line} `int TestInfo::line() const` Returns the line where this test is defined. ##### is_in_another_shard {#TestInfo::is_in_another_shard} `bool TestInfo::is_in_another_shard() const` Returns true if this test should not be run because it's in another shard. ##### should_run {#TestInfo::should_run} `bool TestInfo::should_run() const` Returns true if this test should run, that is if the test is not disabled (or it is disabled but the `also_run_disabled_tests` flag has been specified) and its full name matches the user-specified filter. GoogleTest allows the user to filter the tests by their full names. Only the tests that match the filter will run. See [Running a Subset of the Tests](../advanced.md#running-a-subset-of-the-tests) for more information. ##### is_reportable {#TestInfo::is_reportable} `bool TestInfo::is_reportable() const` Returns true if and only if this test will appear in the XML report. ##### result {#TestInfo::result} `const TestResult* TestInfo::result() const` Returns the result of the test. See [`TestResult`](#TestResult). ### TestParamInfo {#TestParamInfo} `testing::TestParamInfo` Describes a parameter to a value-parameterized test. The type `T` is the type of the parameter. Contains the fields `param` and `index` which hold the value of the parameter and its integer index respectively. ### UnitTest {#UnitTest} `testing::UnitTest` This class contains information about the test program. `UnitTest` is a singleton class. The only instance is created when `UnitTest::GetInstance()` is first called. This instance is never deleted. `UnitTest` is not copyable. #### Public Methods {#UnitTest-public} ##### GetInstance {#UnitTest::GetInstance} `static UnitTest* UnitTest::GetInstance()` Gets the singleton `UnitTest` object. The first time this method is called, a `UnitTest` object is constructed and returned. Consecutive calls will return the same object. ##### original_working_dir {#UnitTest::original_working_dir} `const char* UnitTest::original_working_dir() const` Returns the working directory when the first [`TEST()`](#TEST) or [`TEST_F()`](#TEST_F) was executed. The `UnitTest` object owns the string. ##### current_test_suite {#UnitTest::current_test_suite} `const TestSuite* UnitTest::current_test_suite() const` Returns the [`TestSuite`](#TestSuite) object for the test that's currently running, or `NULL` if no test is running. ##### current_test_info {#UnitTest::current_test_info} `const TestInfo* UnitTest::current_test_info() const` Returns the [`TestInfo`](#TestInfo) object for the test that's currently running, or `NULL` if no test is running. ##### random_seed {#UnitTest::random_seed} `int UnitTest::random_seed() const` Returns the random seed used at the start of the current test run. ##### successful_test_suite_count {#UnitTest::successful_test_suite_count} `int UnitTest::successful_test_suite_count() const` Gets the number of successful test suites. ##### failed_test_suite_count {#UnitTest::failed_test_suite_count} `int UnitTest::failed_test_suite_count() const` Gets the number of failed test suites. ##### total_test_suite_count {#UnitTest::total_test_suite_count} `int UnitTest::total_test_suite_count() const` Gets the number of all test suites. ##### test_suite_to_run_count {#UnitTest::test_suite_to_run_count} `int UnitTest::test_suite_to_run_count() const` Gets the number of all test suites that contain at least one test that should run. ##### successful_test_count {#UnitTest::successful_test_count} `int UnitTest::successful_test_count() const` Gets the number of successful tests. ##### skipped_test_count {#UnitTest::skipped_test_count} `int UnitTest::skipped_test_count() const` Gets the number of skipped tests. ##### failed_test_count {#UnitTest::failed_test_count} `int UnitTest::failed_test_count() const` Gets the number of failed tests. ##### reportable_disabled_test_count {#UnitTest::reportable_disabled_test_count} `int UnitTest::reportable_disabled_test_count() const` Gets the number of disabled tests that will be reported in the XML report. ##### disabled_test_count {#UnitTest::disabled_test_count} `int UnitTest::disabled_test_count() const` Gets the number of disabled tests. ##### reportable_test_count {#UnitTest::reportable_test_count} `int UnitTest::reportable_test_count() const` Gets the number of tests to be printed in the XML report. ##### total_test_count {#UnitTest::total_test_count} `int UnitTest::total_test_count() const` Gets the number of all tests. ##### test_to_run_count {#UnitTest::test_to_run_count} `int UnitTest::test_to_run_count() const` Gets the number of tests that should run. ##### start_timestamp {#UnitTest::start_timestamp} `TimeInMillis UnitTest::start_timestamp() const` Gets the time of the test program start, in ms from the start of the UNIX epoch. ##### elapsed_time {#UnitTest::elapsed_time} `TimeInMillis UnitTest::elapsed_time() const` Gets the elapsed time, in milliseconds. ##### Passed {#UnitTest::Passed} `bool UnitTest::Passed() const` Returns true if and only if the unit test passed (i.e. all test suites passed). ##### Failed {#UnitTest::Failed} `bool UnitTest::Failed() const` Returns true if and only if the unit test failed (i.e. some test suite failed or something outside of all tests failed). ##### GetTestSuite {#UnitTest::GetTestSuite} `const TestSuite* UnitTest::GetTestSuite(int i) const` Gets the [`TestSuite`](#TestSuite) object for the `i`-th test suite among all the test suites. `i` can range from 0 to `total_test_suite_count() - 1`. If `i` is not in that range, returns `NULL`. ##### ad_hoc_test_result {#UnitTest::ad_hoc_test_result} `const TestResult& UnitTest::ad_hoc_test_result() const` Returns the [`TestResult`](#TestResult) containing information on test failures and properties logged outside of individual test suites. ##### listeners {#UnitTest::listeners} `TestEventListeners& UnitTest::listeners()` Returns the list of event listeners that can be used to track events inside GoogleTest. See [`TestEventListeners`](#TestEventListeners). ### TestEventListener {#TestEventListener} `testing::TestEventListener` The interface for tracing execution of tests. The methods below are listed in the order the corresponding events are fired. #### Public Methods {#TestEventListener-public} ##### OnTestProgramStart {#TestEventListener::OnTestProgramStart} `virtual void TestEventListener::OnTestProgramStart(const UnitTest& unit_test)` Fired before any test activity starts. ##### OnTestIterationStart {#TestEventListener::OnTestIterationStart} `virtual void TestEventListener::OnTestIterationStart(const UnitTest& unit_test, int iteration)` Fired before each iteration of tests starts. There may be more than one iteration if `GTEST_FLAG(repeat)` is set. `iteration` is the iteration index, starting from 0. ##### OnEnvironmentsSetUpStart {#TestEventListener::OnEnvironmentsSetUpStart} `virtual void TestEventListener::OnEnvironmentsSetUpStart(const UnitTest& unit_test)` Fired before environment set-up for each iteration of tests starts. ##### OnEnvironmentsSetUpEnd {#TestEventListener::OnEnvironmentsSetUpEnd} `virtual void TestEventListener::OnEnvironmentsSetUpEnd(const UnitTest& unit_test)` Fired after environment set-up for each iteration of tests ends. ##### OnTestSuiteStart {#TestEventListener::OnTestSuiteStart} `virtual void TestEventListener::OnTestSuiteStart(const TestSuite& test_suite)` Fired before the test suite starts. ##### OnTestStart {#TestEventListener::OnTestStart} `virtual void TestEventListener::OnTestStart(const TestInfo& test_info)` Fired before the test starts. ##### OnTestPartResult {#TestEventListener::OnTestPartResult} `virtual void TestEventListener::OnTestPartResult(const TestPartResult& test_part_result)` Fired after a failed assertion or a `SUCCEED()` invocation. If you want to throw an exception from this function to skip to the next test, it must be an [`AssertionException`](#AssertionException) or inherited from it. ##### OnTestEnd {#TestEventListener::OnTestEnd} `virtual void TestEventListener::OnTestEnd(const TestInfo& test_info)` Fired after the test ends. ##### OnTestSuiteEnd {#TestEventListener::OnTestSuiteEnd} `virtual void TestEventListener::OnTestSuiteEnd(const TestSuite& test_suite)` Fired after the test suite ends. ##### OnEnvironmentsTearDownStart {#TestEventListener::OnEnvironmentsTearDownStart} `virtual void TestEventListener::OnEnvironmentsTearDownStart(const UnitTest& unit_test)` Fired before environment tear-down for each iteration of tests starts. ##### OnEnvironmentsTearDownEnd {#TestEventListener::OnEnvironmentsTearDownEnd} `virtual void TestEventListener::OnEnvironmentsTearDownEnd(const UnitTest& unit_test)` Fired after environment tear-down for each iteration of tests ends. ##### OnTestIterationEnd {#TestEventListener::OnTestIterationEnd} `virtual void TestEventListener::OnTestIterationEnd(const UnitTest& unit_test, int iteration)` Fired after each iteration of tests finishes. ##### OnTestProgramEnd {#TestEventListener::OnTestProgramEnd} `virtual void TestEventListener::OnTestProgramEnd(const UnitTest& unit_test)` Fired after all test activities have ended. ### TestEventListeners {#TestEventListeners} `testing::TestEventListeners` Lets users add listeners to track events in GoogleTest. #### Public Methods {#TestEventListeners-public} ##### Append {#TestEventListeners::Append} `void TestEventListeners::Append(TestEventListener* listener)` Appends an event listener to the end of the list. GoogleTest assumes ownership of the listener (i.e. it will delete the listener when the test program finishes). ##### Release {#TestEventListeners::Release} `TestEventListener* TestEventListeners::Release(TestEventListener* listener)` Removes the given event listener from the list and returns it. It then becomes the caller's responsibility to delete the listener. Returns `NULL` if the listener is not found in the list. ##### default_result_printer {#TestEventListeners::default_result_printer} `TestEventListener* TestEventListeners::default_result_printer() const` Returns the standard listener responsible for the default console output. Can be removed from the listeners list to shut down default console output. Note that removing this object from the listener list with [`Release()`](#TestEventListeners::Release) transfers its ownership to the caller and makes this function return `NULL` the next time. ##### default_xml_generator {#TestEventListeners::default_xml_generator} `TestEventListener* TestEventListeners::default_xml_generator() const` Returns the standard listener responsible for the default XML output controlled by the `--gtest_output=xml` flag. Can be removed from the listeners list by users who want to shut down the default XML output controlled by this flag and substitute it with custom one. Note that removing this object from the listener list with [`Release()`](#TestEventListeners::Release) transfers its ownership to the caller and makes this function return `NULL` the next time. ### TestPartResult {#TestPartResult} `testing::TestPartResult` A copyable object representing the result of a test part (i.e. an assertion or an explicit `FAIL()`, `ADD_FAILURE()`, or `SUCCESS()`). #### Public Methods {#TestPartResult-public} ##### type {#TestPartResult::type} `Type TestPartResult::type() const` Gets the outcome of the test part. The return type `Type` is an enum defined as follows: ```cpp enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. kFatalFailure, // Failed and the test should be terminated. kSkip // Skipped. }; ``` ##### file_name {#TestPartResult::file_name} `const char* TestPartResult::file_name() const` Gets the name of the source file where the test part took place, or `NULL` if it's unknown. ##### line_number {#TestPartResult::line_number} `int TestPartResult::line_number() const` Gets the line in the source file where the test part took place, or `-1` if it's unknown. ##### summary {#TestPartResult::summary} `const char* TestPartResult::summary() const` Gets the summary of the failure message. ##### message {#TestPartResult::message} `const char* TestPartResult::message() const` Gets the message associated with the test part. ##### skipped {#TestPartResult::skipped} `bool TestPartResult::skipped() const` Returns true if and only if the test part was skipped. ##### passed {#TestPartResult::passed} `bool TestPartResult::passed() const` Returns true if and only if the test part passed. ##### nonfatally_failed {#TestPartResult::nonfatally_failed} `bool TestPartResult::nonfatally_failed() const` Returns true if and only if the test part non-fatally failed. ##### fatally_failed {#TestPartResult::fatally_failed} `bool TestPartResult::fatally_failed() const` Returns true if and only if the test part fatally failed. ##### failed {#TestPartResult::failed} `bool TestPartResult::failed() const` Returns true if and only if the test part failed. ### TestProperty {#TestProperty} `testing::TestProperty` A copyable object representing a user-specified test property which can be output as a key/value string pair. #### Public Methods {#TestProperty-public} ##### key {#key} `const char* key() const` Gets the user-supplied key. ##### value {#value} `const char* value() const` Gets the user-supplied value. ##### SetValue {#SetValue} `void SetValue(const std::string& new_value)` Sets a new value, overriding the previous one. ### TestResult {#TestResult} `testing::TestResult` Contains information about the result of a single test. `TestResult` is not copyable. #### Public Methods {#TestResult-public} ##### total_part_count {#TestResult::total_part_count} `int TestResult::total_part_count() const` Gets the number of all test parts. This is the sum of the number of successful test parts and the number of failed test parts. ##### test_property_count {#TestResult::test_property_count} `int TestResult::test_property_count() const` Returns the number of test properties. ##### Passed {#TestResult::Passed} `bool TestResult::Passed() const` Returns true if and only if the test passed (i.e. no test part failed). ##### Skipped {#TestResult::Skipped} `bool TestResult::Skipped() const` Returns true if and only if the test was skipped. ##### Failed {#TestResult::Failed} `bool TestResult::Failed() const` Returns true if and only if the test failed. ##### HasFatalFailure {#TestResult::HasFatalFailure} `bool TestResult::HasFatalFailure() const` Returns true if and only if the test fatally failed. ##### HasNonfatalFailure {#TestResult::HasNonfatalFailure} `bool TestResult::HasNonfatalFailure() const` Returns true if and only if the test has a non-fatal failure. ##### elapsed_time {#TestResult::elapsed_time} `TimeInMillis TestResult::elapsed_time() const` Returns the elapsed time, in milliseconds. ##### start_timestamp {#TestResult::start_timestamp} `TimeInMillis TestResult::start_timestamp() const` Gets the time of the test case start, in ms from the start of the UNIX epoch. ##### GetTestPartResult {#TestResult::GetTestPartResult} `const TestPartResult& TestResult::GetTestPartResult(int i) const` Returns the [`TestPartResult`](#TestPartResult) for the `i`-th test part result among all the results. `i` can range from 0 to `total_part_count() - 1`. If `i` is not in that range, aborts the program. ##### GetTestProperty {#TestResult::GetTestProperty} `const TestProperty& TestResult::GetTestProperty(int i) const` Returns the [`TestProperty`](#TestProperty) object for the `i`-th test property. `i` can range from 0 to `test_property_count() - 1`. If `i` is not in that range, aborts the program. ### TimeInMillis {#TimeInMillis} `testing::TimeInMillis` An integer type representing time in milliseconds. ### Types {#Types} `testing::Types` Represents a list of types for use in typed tests and type-parameterized tests. The template argument `T...` can be any number of types, for example: ``` testing::Types ``` See [Typed Tests](../advanced.md#typed-tests) and [Type-Parameterized Tests](../advanced.md#type-parameterized-tests) for more information. ### WithParamInterface {#WithParamInterface} `testing::WithParamInterface` The pure interface class that all value-parameterized tests inherit from. A value-parameterized test fixture class must inherit from both [`Test`](#Test) and `WithParamInterface`. In most cases that just means inheriting from [`TestWithParam`](#TestWithParam), but more complicated test hierarchies may need to inherit from `Test` and `WithParamInterface` at different levels. This interface defines the type alias `ParamType` for the parameter type `T` and has support for accessing the test parameter value via the `GetParam()` method: ``` static const ParamType& GetParam() ``` For more information, see [Value-Parameterized Tests](../advanced.md#value-parameterized-tests). ## Functions GoogleTest defines the following functions to help with writing and running tests. ### InitGoogleTest {#InitGoogleTest} `void testing::InitGoogleTest(int* argc, char** argv)` \ `void testing::InitGoogleTest(int* argc, wchar_t** argv)` \ `void testing::InitGoogleTest()` Initializes GoogleTest. This must be called before calling [`RUN_ALL_TESTS()`](#RUN_ALL_TESTS). In particular, it parses the command line for the flags that GoogleTest recognizes. Whenever a GoogleTest flag is seen, it is removed from `argv`, and `*argc` is decremented. Keep in mind that `argv` must terminate with a `NULL` pointer (i.e. `argv[argc]` is `NULL`), which is already the case with the default `argv` passed to `main`. No value is returned. Instead, the GoogleTest flag variables are updated. The `InitGoogleTest(int* argc, wchar_t** argv)` overload can be used in Windows programs compiled in `UNICODE` mode. The argument-less `InitGoogleTest()` overload can be used on Arduino/embedded platforms where there is no `argc`/`argv`. ### AddGlobalTestEnvironment {#AddGlobalTestEnvironment} `Environment* testing::AddGlobalTestEnvironment(Environment* env)` Adds a test environment to the test program. Must be called before [`RUN_ALL_TESTS()`](#RUN_ALL_TESTS) is called. See [Global Set-Up and Tear-Down](../advanced.md#global-set-up-and-tear-down) for more information. See also [`Environment`](#Environment). ### RegisterTest {#RegisterTest} ```cpp template TestInfo* testing::RegisterTest(const char* test_suite_name, const char* test_name, const char* type_param, const char* value_param, const char* file, int line, Factory factory) ``` Dynamically registers a test with the framework. The `factory` argument is a factory callable (move-constructible) object or function pointer that creates a new instance of the `Test` object. It handles ownership to the caller. The signature of the callable is `Fixture*()`, where `Fixture` is the test fixture class for the test. All tests registered with the same `test_suite_name` must return the same fixture type. This is checked at runtime. The framework will infer the fixture class from the factory and will call the `SetUpTestSuite` and `TearDownTestSuite` methods for it. Must be called before [`RUN_ALL_TESTS()`](#RUN_ALL_TESTS) is invoked, otherwise behavior is undefined. See [Registering tests programmatically](../advanced.md#registering-tests-programmatically) for more information. ### RUN_ALL_TESTS {#RUN_ALL_TESTS} `int RUN_ALL_TESTS()` Use this function in `main()` to run all tests. It returns `0` if all tests are successful, or `1` otherwise. `RUN_ALL_TESTS()` should be invoked after the command line has been parsed by [`InitGoogleTest()`](#InitGoogleTest). This function was formerly a macro; thus, it is in the global namespace and has an all-caps name. ### AssertionSuccess {#AssertionSuccess} `AssertionResult testing::AssertionSuccess()` Creates a successful assertion result. See [`AssertionResult`](#AssertionResult). ### AssertionFailure {#AssertionFailure} `AssertionResult testing::AssertionFailure()` Creates a failed assertion result. Use the `<<` operator to store a failure message: ```cpp testing::AssertionFailure() << "My failure message"; ``` See [`AssertionResult`](#AssertionResult). ### StaticAssertTypeEq {#StaticAssertTypeEq} `testing::StaticAssertTypeEq()` Compile-time assertion for type equality. Compiles if and only if `T1` and `T2` are the same type. The value it returns is irrelevant. See [Type Assertions](../advanced.md#type-assertions) for more information. ### PrintToString {#PrintToString} `std::string testing::PrintToString(x)` Prints any value `x` using GoogleTest's value printer. See [Teaching GoogleTest How to Print Your Values](../advanced.md#teaching-googletest-how-to-print-your-values) for more information. ### PrintToStringParamName {#PrintToStringParamName} `std::string testing::PrintToStringParamName(TestParamInfo& info)` A built-in parameterized test name generator which returns the result of [`PrintToString`](#PrintToString) called on `info.param`. Does not work when the test parameter is a `std::string` or C string. See [Specifying Names for Value-Parameterized Test Parameters](../advanced.md#specifying-names-for-value-parameterized-test-parameters) for more information. See also [`TestParamInfo`](#TestParamInfo) and [`INSTANTIATE_TEST_SUITE_P`](#INSTANTIATE_TEST_SUITE_P). gperftools-gperftools-2.18/vendor/googletest/docs/samples.md000066400000000000000000000021341513545575200244150ustar00rootroot00000000000000# Googletest Samples If you're like us, you'd like to look at [googletest samples.](https://github.com/google/googletest/blob/main/googletest/samples) The sample directory has a number of well-commented samples showing how to use a variety of googletest features. * Sample #1 shows the basic steps of using googletest to test C++ functions. * Sample #2 shows a more complex unit test for a class with multiple member functions. * Sample #3 uses a test fixture. * Sample #4 teaches you how to use googletest and `googletest.h` together to get the best of both libraries. * Sample #5 puts shared testing logic in a base test fixture, and reuses it in derived fixtures. * Sample #6 demonstrates type-parameterized tests. * Sample #7 teaches the basics of value-parameterized tests. * Sample #8 shows using `Combine()` in value-parameterized tests. * Sample #9 shows use of the listener API to modify Google Test's console output and the use of its reflection API to inspect test results. * Sample #10 shows use of the listener API to implement a primitive memory leak checker. gperftools-gperftools-2.18/vendor/googletest/fake_fuchsia_sdk.bzl000066400000000000000000000036661513545575200254740ustar00rootroot00000000000000"""Provides a fake @fuchsia_sdk implementation that's used when the real one isn't available. GoogleTest can be used with the [Fuchsia](https://fuchsia.dev/) SDK. However, because the Fuchsia SDK does not yet support bzlmod, GoogleTest's `MODULE.bazel` file by default provides a "fake" Fuchsia SDK. To override this and use the real Fuchsia SDK, you can add the following to your project's `MODULE.bazel` file: fake_fuchsia_sdk_extension = use_extension("@com_google_googletest//:fake_fuchsia_sdk.bzl", "fuchsia_sdk") override_repo(fake_fuchsia_sdk_extension, "fuchsia_sdk") NOTE: The `override_repo` built-in is only available in Bazel 8.0 and higher. See https://github.com/google/googletest/issues/4472 for more details of why the fake Fuchsia SDK is needed. """ def _fake_fuchsia_sdk_impl(repo_ctx): for stub_target in repo_ctx.attr._stub_build_targets: stub_package = stub_target stub_target_name = stub_target.split("/")[-1] repo_ctx.file("%s/BUILD.bazel" % stub_package, """ filegroup( name = "%s", ) """ % stub_target_name) fake_fuchsia_sdk = repository_rule( doc = "Used to create a fake @fuchsia_sdk repository with stub build targets.", implementation = _fake_fuchsia_sdk_impl, attrs = { "_stub_build_targets": attr.string_list( doc = "The stub build targets to initialize.", default = [ "pkg/fdio", "pkg/syslog", "pkg/zx", ], ), }, ) _create_fake = tag_class() def _fuchsia_sdk_impl(module_ctx): create_fake_sdk = False for mod in module_ctx.modules: for _ in mod.tags.create_fake: create_fake_sdk = True if create_fake_sdk: fake_fuchsia_sdk(name = "fuchsia_sdk") return module_ctx.extension_metadata(reproducible = True) fuchsia_sdk = module_extension( implementation = _fuchsia_sdk_impl, tag_classes = {"create_fake": _create_fake}, ) gperftools-gperftools-2.18/vendor/googletest/googlemock/000077500000000000000000000000001513545575200236255ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/googlemock/CMakeLists.txt000066400000000000000000000174341513545575200263760ustar00rootroot00000000000000######################################################################## # Note: CMake support is community-based. The maintainers do not use CMake # internally. # # CMake build script for Google Mock. # # To run the tests for Google Mock itself on Linux, use 'make test' or # ctest. You can select which tests to run using 'ctest -R regex'. # For more options, run 'ctest --help'. option(gmock_build_tests "Build all of Google Mock's own tests." OFF) # A directory to find Google Test sources. if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt") set(gtest_dir gtest) else() set(gtest_dir ../googletest) endif() # Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). include("${gtest_dir}/cmake/hermetic_build.cmake" OPTIONAL) if (COMMAND pre_project_set_up_hermetic_build) # Google Test also calls hermetic setup functions from add_subdirectory, # although its changes will not affect things at the current scope. pre_project_set_up_hermetic_build() endif() ######################################################################## # # Project-wide settings # Name of the project. # # CMake files in this project can refer to the root source directory # as ${gmock_SOURCE_DIR} and to the root binary directory as # ${gmock_BINARY_DIR}. # Language "C" is required for find_package(Threads). cmake_minimum_required(VERSION 3.13) project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C) if (COMMAND set_up_hermetic_build) set_up_hermetic_build() endif() # Instructs CMake to process Google Test's CMakeLists.txt and add its # targets to the current scope. We are placing Google Test's binary # directory in a subdirectory of our own as VC compilation may break # if they are the same (the default). add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/${gtest_dir}") # These commands only run if this is the main project if(CMAKE_PROJECT_NAME STREQUAL "gmock" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution") # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to # make it prominent in the GUI. option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) else() mark_as_advanced(gmock_build_tests) endif() # Although Google Test's CMakeLists.txt calls this function, the # changes there don't affect the current scope. Therefore we have to # call it again here. config_compiler_and_linker() # from ${gtest_dir}/cmake/internal_utils.cmake # Adds Google Mock's and Google Test's header directories to the search path. # Get Google Test's include dirs from the target, gtest_SOURCE_DIR is broken # when using fetch-content with the name "GTest". get_target_property(gtest_include_dirs gtest INCLUDE_DIRECTORIES) set(gmock_build_include_dirs "${gmock_SOURCE_DIR}/include" "${gmock_SOURCE_DIR}" "${gtest_include_dirs}") include_directories(${gmock_build_include_dirs}) ######################################################################## # # Defines the gmock & gmock_main libraries. User tests should link # with one of them. # Google Mock libraries. We build them using more strict warnings than what # are used for other targets, to ensure that Google Mock can be compiled by # a user aggressive about warnings. if (MSVC) cxx_library(gmock "${cxx_strict}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc) cxx_library(gmock_main "${cxx_strict}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) else() cxx_library(gmock "${cxx_strict}" src/gmock-all.cc) target_link_libraries(gmock PUBLIC gtest) set_target_properties(gmock PROPERTIES VERSION ${GOOGLETEST_VERSION}) cxx_library(gmock_main "${cxx_strict}" src/gmock_main.cc) target_link_libraries(gmock_main PUBLIC gmock) set_target_properties(gmock_main PROPERTIES VERSION ${GOOGLETEST_VERSION}) endif() string(REPLACE ";" "$" dirs "${gmock_build_include_dirs}") target_include_directories(gmock SYSTEM INTERFACE "$" "$/${CMAKE_INSTALL_INCLUDEDIR}>") target_include_directories(gmock_main SYSTEM INTERFACE "$" "$/${CMAKE_INSTALL_INCLUDEDIR}>") ######################################################################## # # Install rules. install_project(gmock gmock_main) ######################################################################## # # Google Mock's own tests. # # You can skip this section if you aren't interested in testing # Google Mock itself. # # The tests are not built by default. To build them, set the # gmock_build_tests option to ON. You can do it by running ccmake # or specifying the -Dgmock_build_tests=ON flag when running cmake. if (gmock_build_tests) # This must be set in the root directory for the tests to be run by # 'make test' or ctest. enable_testing() if (MINGW OR CYGWIN) add_compile_options("-Wa,-mbig-obj") endif() ############################################################ # C++ tests built with standard compiler flags. cxx_test(gmock-actions_test gmock_main) cxx_test(gmock-cardinalities_test gmock_main) cxx_test(gmock_ex_test gmock_main) cxx_test(gmock-function-mocker_test gmock_main) cxx_test(gmock-internal-utils_test gmock_main) cxx_test(gmock-matchers-arithmetic_test gmock_main) cxx_test(gmock-matchers-comparisons_test gmock_main) cxx_test(gmock-matchers-containers_test gmock_main) cxx_test(gmock-matchers-misc_test gmock_main) cxx_test(gmock-more-actions_test gmock_main) cxx_test(gmock-nice-strict_test gmock_main) cxx_test(gmock-port_test gmock_main) cxx_test(gmock-spec-builders_test gmock_main) cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc) cxx_test(gmock_test gmock_main) if (DEFINED GTEST_HAS_PTHREAD) cxx_test(gmock_stress_test gmock) endif() # gmock_all_test is commented to save time building and running tests. # Uncomment if necessary. # cxx_test(gmock_all_test gmock_main) ############################################################ # C++ tests built with non-standard compiler flags. if (MSVC) cxx_library(gmock_main_no_exception "${cxx_no_exception}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) else() cxx_library(gmock_main_no_exception "${cxx_no_exception}" src/gmock_main.cc) target_link_libraries(gmock_main_no_exception PUBLIC gmock) cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" src/gmock_main.cc) target_link_libraries(gmock_main_no_rtti PUBLIC gmock) endif() cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}" gmock_main_no_exception test/gmock-more-actions_test.cc) cxx_test_with_flags(gmock_no_rtti_test "${cxx_no_rtti}" gmock_main_no_rtti test/gmock-spec-builders_test.cc) cxx_shared_library(shared_gmock_main "${cxx_default}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) # Tests that a binary can be built with Google Mock as a shared library. On # some system configurations, it may not possible to run the binary without # knowing more details about the system configurations. We do not try to run # this binary. To get a more robust shared library coverage, configure with # -DBUILD_SHARED_LIBS=ON. cxx_executable_with_flags(shared_gmock_test_ "${cxx_default}" shared_gmock_main test/gmock-spec-builders_test.cc) set_target_properties(shared_gmock_test_ PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") ############################################################ # Python tests. cxx_executable(gmock_leak_test_ test gmock_main) py_test(gmock_leak_test) cxx_executable(gmock_output_test_ test gmock) py_test(gmock_output_test) endif() gperftools-gperftools-2.18/vendor/googletest/googlemock/README.md000066400000000000000000000030011513545575200250760ustar00rootroot00000000000000# Googletest Mocking (gMock) Framework ### Overview Google's framework for writing and using C++ mock classes. It can help you derive better designs of your system and write better tests. It is inspired by: * [jMock](http://www.jmock.org/) * [EasyMock](https://easymock.org/) * [Hamcrest](https://code.google.com/p/hamcrest/) It is designed with C++'s specifics in mind. gMock: - Provides a declarative syntax for defining mocks. - Can define partial (hybrid) mocks, which are a cross of real and mock objects. - Handles functions of arbitrary types and overloaded functions. - Comes with a rich set of matchers for validating function arguments. - Uses an intuitive syntax for controlling the behavior of a mock. - Does automatic verification of expectations (no record-and-replay needed). - Allows arbitrary (partial) ordering constraints on function calls to be expressed. - Lets a user extend it by defining new matchers and actions. - Does not use exceptions. - Is easy to learn and use. Details and examples can be found here: * [gMock for Dummies](https://google.github.io/googletest/gmock_for_dummies.html) * [Legacy gMock FAQ](https://google.github.io/googletest/gmock_faq.html) * [gMock Cookbook](https://google.github.io/googletest/gmock_cook_book.html) * [gMock Cheat Sheet](https://google.github.io/googletest/gmock_cheat_sheet.html) GoogleMock is a part of [GoogleTest C++ testing framework](https://github.com/google/googletest/) and a subject to the same requirements. gperftools-gperftools-2.18/vendor/googletest/googlemock/cmake/000077500000000000000000000000001513545575200247055ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/googlemock/cmake/gmock.pc.in000066400000000000000000000005331513545575200267370ustar00rootroot00000000000000libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: gmock Description: GoogleMock (without main() function) Version: @PROJECT_VERSION@ URL: https://github.com/google/googletest Requires: gtest = @PROJECT_VERSION@ Libs: -L${libdir} -lgmock @CMAKE_THREAD_LIBS_INIT@ Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ gperftools-gperftools-2.18/vendor/googletest/googlemock/cmake/gmock_main.pc.in000066400000000000000000000005421513545575200277430ustar00rootroot00000000000000libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: gmock_main Description: GoogleMock (with main() function) Version: @PROJECT_VERSION@ URL: https://github.com/google/googletest Requires: gmock = @PROJECT_VERSION@ Libs: -L${libdir} -lgmock_main @CMAKE_THREAD_LIBS_INIT@ Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ gperftools-gperftools-2.18/vendor/googletest/googlemock/docs/000077500000000000000000000000001513545575200245555ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/googlemock/docs/README.md000066400000000000000000000002131513545575200260300ustar00rootroot00000000000000# Content Moved We are working on updates to the GoogleTest documentation, which has moved to the top-level [docs](../../docs) directory. gperftools-gperftools-2.18/vendor/googletest/googlemock/include/000077500000000000000000000000001513545575200252505ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/googlemock/include/gmock/000077500000000000000000000000001513545575200263505ustar00rootroot00000000000000gperftools-gperftools-2.18/vendor/googletest/googlemock/include/gmock/gmock-actions.h000066400000000000000000002637301513545575200312720ustar00rootroot00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Google Mock - a framework for writing C++ mock classes. // // The ACTION* family of macros can be used in a namespace scope to // define custom actions easily. The syntax: // // ACTION(name) { statements; } // // will define an action with the given name that executes the // statements. The value returned by the statements will be used as // the return value of the action. Inside the statements, you can // refer to the K-th (0-based) argument of the mock function by // 'argK', and refer to its type by 'argK_type'. For example: // // ACTION(IncrementArg1) { // arg1_type temp = arg1; // return ++(*temp); // } // // allows you to write // // ...WillOnce(IncrementArg1()); // // You can also refer to the entire argument tuple and its type by // 'args' and 'args_type', and refer to the mock function type and its // return type by 'function_type' and 'return_type'. // // Note that you don't need to specify the types of the mock function // arguments. However rest assured that your code is still type-safe: // you'll get a compiler error if *arg1 doesn't support the ++ // operator, or if the type of ++(*arg1) isn't compatible with the // mock function's return type, for example. // // Sometimes you'll want to parameterize the action. For that you can use // another macro: // // ACTION_P(name, param_name) { statements; } // // For example: // // ACTION_P(Add, n) { return arg0 + n; } // // will allow you to write: // // ...WillOnce(Add(5)); // // Note that you don't need to provide the type of the parameter // either. If you need to reference the type of a parameter named // 'foo', you can write 'foo_type'. For example, in the body of // ACTION_P(Add, n) above, you can write 'n_type' to refer to the type // of 'n'. // // We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support // multi-parameter actions. // // For the purpose of typing, you can view // // ACTION_Pk(Foo, p1, ..., pk) { ... } // // as shorthand for // // template // FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } // // In particular, you can provide the template type arguments // explicitly when invoking Foo(), as in Foo(5, false); // although usually you can rely on the compiler to infer the types // for you automatically. You can assign the result of expression // Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. // // You can also overload actions with different numbers of parameters: // // ACTION_P(Plus, a) { ... } // ACTION_P2(Plus, a, b) { ... } // // While it's tempting to always use the ACTION* macros when defining // a new action, you should also consider implementing ActionInterface // or using MakePolymorphicAction() instead, especially if you need to // use the action a lot. While these approaches require more work, // they give you more control on the types of the mock function // arguments and the action parameters, which in general leads to // better compiler error messages that pay off in the long run. They // also allow overloading actions based on parameter types (as opposed // to just based on the number of parameters). // // CAVEAT: // // ACTION*() can only be used in a namespace scope as templates cannot be // declared inside of a local class. // Users can, however, define any local functors (e.g. a lambda) that // can be used as actions. // // MORE INFORMATION: // // To learn more about using these macros, please search for 'ACTION' on // https://github.com/google/googletest/blob/main/docs/gmock_cook_book.md // IWYU pragma: private, include "gmock/gmock.h" // IWYU pragma: friend gmock/.* #ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ #define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ #ifndef _WIN32_WCE #include #endif #include #include #include #include #include #include #include #include #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" #include "gmock/internal/gmock-pp.h" GTEST_DISABLE_MSC_WARNINGS_PUSH_(4100) namespace testing { // To implement an action Foo, define: // 1. a class FooAction that implements the ActionInterface interface, and // 2. a factory function that creates an Action object from a // const FooAction*. // // The two-level delegation design follows that of Matcher, providing // consistency for extension developers. It also eases ownership // management as Action objects can now be copied like plain values. namespace internal { // BuiltInDefaultValueGetter::Get() returns a // default-constructed T value. BuiltInDefaultValueGetter::Get() crashes with an error. // // This primary template is used when kDefaultConstructible is true. template struct BuiltInDefaultValueGetter { static T Get() { return T(); } }; template struct BuiltInDefaultValueGetter { static T Get() { Assert(false, __FILE__, __LINE__, "Default action undefined for the function return type."); #if defined(__GNUC__) || defined(__clang__) __builtin_unreachable(); #elif defined(_MSC_VER) __assume(0); #else return Invalid(); // The above statement will never be reached, but is required in // order for this function to compile. #endif } }; // BuiltInDefaultValue::Get() returns the "built-in" default value // for type T, which is NULL when T is a raw pointer type, 0 when T is // a numeric type, false when T is bool, or "" when T is string or // std::string. In addition, in C++11 and above, it turns a // default-constructed T value if T is default constructible. For any // other type T, the built-in default T value is undefined, and the // function will abort the process. template class BuiltInDefaultValue { public: // This function returns true if and only if type T has a built-in default // value. static bool Exists() { return ::std::is_default_constructible::value; } static T Get() { return BuiltInDefaultValueGetter< T, ::std::is_default_constructible::value>::Get(); } }; // This partial specialization says that we use the same built-in // default value for T and const T. template class BuiltInDefaultValue { public: static bool Exists() { return BuiltInDefaultValue::Exists(); } static T Get() { return BuiltInDefaultValue::Get(); } }; // This partial specialization defines the default values for pointer // types. template class BuiltInDefaultValue { public: static bool Exists() { return true; } static T* Get() { return nullptr; } }; // The following specializations define the default values for // specific types we care about. #define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ template <> \ class BuiltInDefaultValue { \ public: \ static bool Exists() { return true; } \ static type Get() { return value; } \ } GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0'); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0'); // There's no need for a default action for signed wchar_t, as that // type is the same as wchar_t for gcc, and invalid for MSVC. // // There's also no need for a default action for unsigned wchar_t, as // that type is the same as unsigned int for gcc, and invalid for // MSVC. #if GMOCK_WCHAR_T_IS_NATIVE_ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT #endif GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long long, 0); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long long, 0); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); #undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ // Partial implementations of metaprogramming types from the standard library // not available in C++11. template struct negation // NOLINTNEXTLINE : std::integral_constant {}; // Base case: with zero predicates the answer is always true. template struct conjunction : std::true_type {}; // With a single predicate, the answer is that predicate. template struct conjunction : P1 {}; // With multiple predicates the answer is the first predicate if that is false, // and we recurse otherwise. template struct conjunction : std::conditional, P1>::type {}; template struct disjunction : std::false_type {}; template struct disjunction : P1 {}; template struct disjunction // NOLINTNEXTLINE : std::conditional, P1>::type {}; template using void_t = void; // Detects whether an expression of type `From` can be implicitly converted to // `To` according to [conv]. In C++17, [conv]/3 defines this as follows: // // An expression e can be implicitly converted to a type T if and only if // the declaration T t=e; is well-formed, for some invented temporary // variable t ([dcl.init]). // // [conv]/2 implies we can use function argument passing to detect whether this // initialization is valid. // // Note that this is distinct from is_convertible, which requires this be valid: // // To test() { // return declval(); // } // // In particular, is_convertible doesn't give the correct answer when `To` and // `From` are the same non-moveable type since `declval` will be an rvalue // reference, defeating the guaranteed copy elision that would otherwise make // this function work. // // REQUIRES: `From` is not cv void. template struct is_implicitly_convertible { private: // A function that accepts a parameter of type T. This can be called with type // U successfully only if U is implicitly convertible to T. template static void Accept(T); // A function that creates a value of type T. template static T Make(); // An overload be selected when implicit conversion from T to To is possible. template (Make()))> static std::true_type TestImplicitConversion(int); // A fallback overload selected in all other cases. template static std::false_type TestImplicitConversion(...); public: using type = decltype(TestImplicitConversion(0)); static constexpr bool value = type::value; }; // Like std::invoke_result_t from C++17, but works only for objects with call // operators (not e.g. member function pointers, which we don't need specific // support for in OnceAction because std::function deals with them). template using call_result_t = decltype(std::declval()(std::declval()...)); template struct is_callable_r_impl : std::false_type {}; // Specialize the struct for those template arguments where call_result_t is // well-formed. When it's not, the generic template above is chosen, resulting // in std::false_type. template struct is_callable_r_impl>, R, F, Args...> : std::conditional< std::is_void::value, // std::true_type, // is_implicitly_convertible, R>>::type {}; // Like std::is_invocable_r from C++17, but works only for objects with call // operators. See the note on call_result_t. template using is_callable_r = is_callable_r_impl; // Like std::as_const from C++17. template typename std::add_const::type& as_const(T& t) { return t; } } // namespace internal // Specialized for function types below. template class OnceAction; // An action that can only be used once. // // This is accepted by WillOnce, which doesn't require the underlying action to // be copy-constructible (only move-constructible), and promises to invoke it as // an rvalue reference. This allows the action to work with move-only types like // std::move_only_function in a type-safe manner. // // For example: // // // Assume we have some API that needs to accept a unique pointer to some // // non-copyable object Foo. // void AcceptUniquePointer(std::unique_ptr foo); // // // We can define an action that provides a Foo to that API. Because It // // has to give away its unique pointer, it must not be called more than // // once, so its call operator is &&-qualified. // struct ProvideFoo { // std::unique_ptr foo; // // void operator()() && { // AcceptUniquePointer(std::move(Foo)); // } // }; // // // This action can be used with WillOnce. // EXPECT_CALL(mock, Call) // .WillOnce(ProvideFoo{std::make_unique(...)}); // // // But a call to WillRepeatedly will fail to compile. This is correct, // // since the action cannot correctly be used repeatedly. // EXPECT_CALL(mock, Call) // .WillRepeatedly(ProvideFoo{std::make_unique(...)}); // // A less-contrived example would be an action that returns an arbitrary type, // whose &&-qualified call operator is capable of dealing with move-only types. template class OnceAction final { private: // True iff we can use the given callable type (or lvalue reference) directly // via StdFunctionAdaptor. template using IsDirectlyCompatible = internal::conjunction< // It must be possible to capture the callable in StdFunctionAdaptor. std::is_constructible::type, Callable>, // The callable must be compatible with our signature. internal::is_callable_r::type, Args...>>; // True iff we can use the given callable type via StdFunctionAdaptor once we // ignore incoming arguments. template using IsCompatibleAfterIgnoringArguments = internal::conjunction< // It must be possible to capture the callable in a lambda. std::is_constructible::type, Callable>, // The callable must be invocable with zero arguments, returning something // convertible to Result. internal::is_callable_r::type>>; public: // Construct from a callable that is directly compatible with our mocked // signature: it accepts our function type's arguments and returns something // convertible to our result type. template ::type>>, IsDirectlyCompatible> // ::value, int>::type = 0> OnceAction(Callable&& callable) // NOLINT : function_(StdFunctionAdaptor::type>( {}, std::forward(callable))) {} // As above, but for a callable that ignores the mocked function's arguments. template ::type>>, // Exclude callables for which the overload above works. // We'd rather provide the arguments if possible. internal::negation>, IsCompatibleAfterIgnoringArguments>::value, int>::type = 0> OnceAction(Callable&& callable) // NOLINT // Call the constructor above with a callable // that ignores the input arguments. : OnceAction(IgnoreIncomingArguments::type>{ std::forward(callable)}) {} // We are naturally copyable because we store only an std::function, but // semantically we should not be copyable. OnceAction(const OnceAction&) = delete; OnceAction& operator=(const OnceAction&) = delete; OnceAction(OnceAction&&) = default; // Invoke the underlying action callable with which we were constructed, // handing it the supplied arguments. Result Call(Args... args) && { return function_(std::forward(args)...); } private: // An adaptor that wraps a callable that is compatible with our signature and // being invoked as an rvalue reference so that it can be used as an // StdFunctionAdaptor. This throws away type safety, but that's fine because // this is only used by WillOnce, which we know calls at most once. // // Once we have something like std::move_only_function from C++23, we can do // away with this. template class StdFunctionAdaptor final { public: // A tag indicating that the (otherwise universal) constructor is accepting // the callable itself, instead of e.g. stealing calls for the move // constructor. struct CallableTag final {}; template explicit StdFunctionAdaptor(CallableTag, F&& callable) : callable_(std::make_shared(std::forward(callable))) {} // Rather than explicitly returning Result, we return whatever the wrapped // callable returns. This allows for compatibility with existing uses like // the following, when the mocked function returns void: // // EXPECT_CALL(mock_fn_, Call) // .WillOnce([&] { // [...] // return 0; // }); // // Such a callable can be turned into std::function. If we use an // explicit return type of Result here then it *doesn't* work with // std::function, because we'll get a "void function should not return a // value" error. // // We need not worry about incompatible result types because the SFINAE on // OnceAction already checks this for us. std::is_invocable_r_v itself makes // the same allowance for void result types. template internal::call_result_t operator()( ArgRefs&&... args) const { return std::move(*callable_)(std::forward(args)...); } private: // We must put the callable on the heap so that we are copyable, which // std::function needs. std::shared_ptr callable_; }; // An adaptor that makes a callable that accepts zero arguments callable with // our mocked arguments. template struct IgnoreIncomingArguments { internal::call_result_t operator()(Args&&...) { return std::move(callable)(); } Callable callable; }; std::function function_; }; // When an unexpected function call is encountered, Google Mock will // let it return a default value if the user has specified one for its // return type, or if the return type has a built-in default value; // otherwise Google Mock won't know what value to return and will have // to abort the process. // // The DefaultValue class allows a user to specify the // default value for a type T that is both copyable and publicly // destructible (i.e. anything that can be used as a function return // type). The usage is: // // // Sets the default value for type T to be foo. // DefaultValue::Set(foo); template class DefaultValue { public: // Sets the default value for type T; requires T to be // copy-constructable and have a public destructor. static void Set(T x) { delete producer_; producer_ = new FixedValueProducer(x); } // Provides a factory function to be called to generate the default value. // This method can be used even if T is only move-constructible, but it is not // limited to that case. typedef T (*FactoryFunction)(); static void SetFactory(FactoryFunction factory) { delete producer_; producer_ = new FactoryValueProducer(factory); } // Unsets the default value for type T. static void Clear() { delete producer_; producer_ = nullptr; } // Returns true if and only if the user has set the default value for type T. static bool IsSet() { return producer_ != nullptr; } // Returns true if T has a default return value set by the user or there // exists a built-in default value. static bool Exists() { return IsSet() || internal::BuiltInDefaultValue::Exists(); } // Returns the default value for type T if the user has set one; // otherwise returns the built-in default value. Requires that Exists() // is true, which ensures that the return value is well-defined. static T Get() { return producer_ == nullptr ? internal::BuiltInDefaultValue::Get() : producer_->Produce(); } private: class ValueProducer { public: virtual ~ValueProducer() = default; virtual T Produce() = 0; }; class FixedValueProducer : public ValueProducer { public: explicit FixedValueProducer(T value) : value_(value) {} T Produce() override { return value_; } private: const T value_; FixedValueProducer(const FixedValueProducer&) = delete; FixedValueProducer& operator=(const FixedValueProducer&) = delete; }; class FactoryValueProducer : public ValueProducer { public: explicit FactoryValueProducer(FactoryFunction factory) : factory_(factory) {} T Produce() override { return factory_(); } private: const FactoryFunction factory_; FactoryValueProducer(const FactoryValueProducer&) = delete; FactoryValueProducer& operator=(const FactoryValueProducer&) = delete; }; static ValueProducer* producer_; }; // This partial specialization allows a user to set default values for // reference types. template class DefaultValue { public: // Sets the default value for type T&. static void Set(T& x) { // NOLINT address_ = &x; } // Unsets the default value for type T&. static void Clear() { address_ = nullptr; } // Returns true if and only if the user has set the default value for type T&. static bool IsSet() { return address_ != nullptr; } // Returns true if T has a default return value set by the user or there // exists a built-in default value. static bool Exists() { return IsSet() || internal::BuiltInDefaultValue::Exists(); } // Returns the default value for type T& if the user has set one; // otherwise returns the built-in default value if there is one; // otherwise aborts the process. static T& Get() { return address_ == nullptr ? internal::BuiltInDefaultValue::Get() : *address_; } private: static T* address_; }; // This specialization allows DefaultValue::Get() to // compile. template <> class DefaultValue { public: static bool Exists() { return true; } static void Get() {} }; // Points to the user-set default value for type T. template typename DefaultValue::ValueProducer* DefaultValue::producer_ = nullptr; // Points to the user-set default value for type T&. template T* DefaultValue::address_ = nullptr; // Implement this interface to define an action for function type F. template class ActionInterface { public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; ActionInterface() = default; virtual ~ActionInterface() = default; // Performs the action. This method is not const, as in general an // action can have side effects and be stateful. For example, a // get-the-next-element-from-the-collection action will need to // remember the current element. virtual Result Perform(const ArgumentTuple& args) = 0; private: ActionInterface(const ActionInterface&) = delete; ActionInterface& operator=(const ActionInterface&) = delete; }; template class Action; // An Action is a copyable and IMMUTABLE (except by assignment) // object that represents an action to be taken when a mock function of type // R(Args...) is called. The implementation of Action is just a // std::shared_ptr to const ActionInterface. Don't inherit from Action! You // can view an object implementing ActionInterface as a concrete action // (including its current state), and an Action object as a handle to it. template class Action { private: using F = R(Args...); // Adapter class to allow constructing Action from a legacy ActionInterface. // New code should create Actions from functors instead. struct ActionAdapter { // Adapter must be copyable to satisfy std::function requirements. ::std::shared_ptr> impl_; template typename internal::Function::Result operator()(InArgs&&... args) { return impl_->Perform( ::std::forward_as_tuple(::std::forward(args)...)); } }; template using IsCompatibleFunctor = std::is_constructible, G>; public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; // Constructs a null Action. Needed for storing Action objects in // STL containers. Action() = default; // Construct an Action from a specified callable. // This cannot take std::function directly, because then Action would not be // directly constructible from lambda (it would require two conversions). template < typename G, typename = typename std::enable_if, std::is_constructible, G>>::value>::type> Action(G&& fun) { // NOLINT Init(::std::forward(fun), IsCompatibleFunctor()); } // Constructs an Action from its implementation. explicit Action(ActionInterface* impl) : fun_(ActionAdapter{::std::shared_ptr>(impl)}) {} // This constructor allows us to turn an Action object into an // Action, as long as F's arguments can be implicitly converted // to Func's and Func's return type can be implicitly converted to F's. template Action(const Action& action) // NOLINT : fun_(action.fun_) {} // Returns true if and only if this is the DoDefault() action. bool IsDoDefault() const { return fun_ == nullptr; } // Performs the action. Note that this method is const even though // the corresponding method in ActionInterface is not. The reason // is that a const Action means that it cannot be re-bound to // another concrete action, not that the concrete action it binds to // cannot change state. (Think of the difference between a const // pointer and a pointer to const.) Result Perform(ArgumentTuple args) const { if (IsDoDefault()) { internal::IllegalDoDefault(__FILE__, __LINE__); } return internal::Apply(fun_, ::std::move(args)); } // An action can be used as a OnceAction, since it's obviously safe to call it // once. operator OnceAction() const { // NOLINT // Return a OnceAction-compatible callable that calls Perform with the // arguments it is provided. We could instead just return fun_, but then // we'd need to handle the IsDoDefault() case separately. struct OA { Action action; R operator()(Args... args) && { return action.Perform( std::forward_as_tuple(std::forward(args)...)); } }; return OA{*this}; } private: template friend class Action; template void Init(G&& g, ::std::true_type) { fun_ = ::std::forward(g); } template void Init(G&& g, ::std::false_type) { fun_ = IgnoreArgs::type>{::std::forward(g)}; } template struct IgnoreArgs { template Result operator()(const InArgs&...) const { return function_impl(); } template Result operator()(const InArgs&...) { return function_impl(); } FunctionImpl function_impl; }; // fun_ is an empty function if and only if this is the DoDefault() action. ::std::function fun_; }; // The PolymorphicAction class template makes it easy to implement a // polymorphic action (i.e. an action that can be used in mock // functions of than one type, e.g. Return()). // // To define a polymorphic action, a user first provides a COPYABLE // implementation class that has a Perform() method template: // // class FooAction { // public: // template // Result Perform(const ArgumentTuple& args) const { // // Processes the arguments and returns a result, using // // std::get(args) to get the N-th (0-based) argument in the tuple. // } // ... // }; // // Then the user creates the polymorphic action using // MakePolymorphicAction(object) where object has type FooAction. See // the definition of Return(void) and SetArgumentPointee(value) for // complete examples. template class PolymorphicAction { public: explicit PolymorphicAction(const Impl& impl) : impl_(impl) {} template operator Action() const { return Action(new MonomorphicImpl(impl_)); } private: template class MonomorphicImpl : public ActionInterface { public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} Result Perform(const ArgumentTuple& args) override { return impl_.template Perform(args); } private: Impl impl_; }; Impl impl_; }; // Creates an Action from its implementation and returns it. The // created Action object owns the implementation. template Action MakeAction(ActionInterface* impl) { return Action(impl); } // Creates a polymorphic action from its implementation. This is // easier to use than the PolymorphicAction constructor as it // doesn't require you to explicitly write the template argument, e.g. // // MakePolymorphicAction(foo); // vs // PolymorphicAction(foo); template inline PolymorphicAction MakePolymorphicAction(const Impl& impl) { return PolymorphicAction(impl); } namespace internal { // Helper struct to specialize ReturnAction to execute a move instead of a copy // on return. Useful for move-only types, but could be used on any type. template struct ByMoveWrapper { explicit ByMoveWrapper(T value) : payload(std::move(value)) {} T payload; }; // The general implementation of Return(R). Specializations follow below. template class ReturnAction final { public: explicit ReturnAction(R value) : value_(std::move(value)) {} template >, // negation>, // std::is_convertible, // std::is_move_constructible>::value>::type> operator OnceAction() && { // NOLINT return Impl(std::move(value_)); } template >, // negation>, // std::is_convertible, // std::is_copy_constructible>::value>::type> operator Action() const { // NOLINT return Impl(value_); } private: // Implements the Return(x) action for a mock function that returns type U. template class Impl final { public: // The constructor used when the return value is allowed to move from the // input value (i.e. we are converting to OnceAction). explicit Impl(R&& input_value) : state_(new State(std::move(input_value))) {} // The constructor used when the return value is not allowed to move from // the input value (i.e. we are converting to Action). explicit Impl(const R& input_value) : state_(new State(input_value)) {} U operator()() && { return std::move(state_->value); } U operator()() const& { return state_->value; } private: // We put our state on the heap so that the compiler-generated copy/move // constructors work correctly even when U is a reference-like type. This is // necessary only because we eagerly create State::value (see the note on // that symbol for details). If we instead had only the input value as a // member then the default constructors would work fine. // // For example, when R is std::string and U is std::string_view, value is a // reference to the string backed by input_value. The copy constructor would // copy both, so that we wind up with a new input_value object (with the // same contents) and a reference to the *old* input_value object rather // than the new one. struct State { explicit State(const R& input_value_in) : input_value(input_value_in), // Make an implicit conversion to Result before initializing the U // object we store, avoiding calling any explicit constructor of U // from R. // // This simulates the language rules: a function with return type U // that does `return R()` requires R to be implicitly convertible to // U, and uses that path for the conversion, even U Result has an // explicit constructor from R. value(ImplicitCast_(internal::as_const(input_value))) {} // As above, but for the case where we're moving from the ReturnAction // object because it's being used as a OnceAction. explicit State(R&& input_value_in) : input_value(std::move(input_value_in)), // For the same reason as above we make an implicit conversion to U // before initializing the value. // // Unlike above we provide the input value as an rvalue to the // implicit conversion because this is a OnceAction: it's fine if it // wants to consume the input value. value(ImplicitCast_(std::move(input_value))) {} // A copy of the value originally provided by the user. We retain this in // addition to the value of the mock function's result type below in case // the latter is a reference-like type. See the std::string_view example // in the documentation on Return. R input_value; // The value we actually return, as the type returned by the mock function // itself. // // We eagerly initialize this here, rather than lazily doing the implicit // conversion automatically each time Perform is called, for historical // reasons: in 2009-11, commit a070cbd91c (Google changelist 13540126) // made the Action conversion operator eagerly convert the R value to // U, but without keeping the R alive. This broke the use case discussed // in the documentation for Return, making reference-like types such as // std::string_view not safe to use as U where the input type R is a // value-like type such as std::string. // // The example the commit gave was not very clear, nor was the issue // thread (https://github.com/google/googlemock/issues/86), but it seems // the worry was about reference-like input types R that flatten to a // value-like type U when being implicitly converted. An example of this // is std::vector::reference, which is often a proxy type with an // reference to the underlying vector: // // // Helper method: have the mock function return bools according // // to the supplied script. // void SetActions(MockFunction& mock, // const std::vector& script) { // for (size_t i = 0; i < script.size(); ++i) { // EXPECT_CALL(mock, Call(i)).WillOnce(Return(script[i])); // } // } // // TEST(Foo, Bar) { // // Set actions using a temporary vector, whose operator[] // // returns proxy objects that references that will be // // dangling once the call to SetActions finishes and the // // vector is destroyed. // MockFunction mock; // SetActions(mock, {false, true}); // // EXPECT_FALSE(mock.AsStdFunction()(0)); // EXPECT_TRUE(mock.AsStdFunction()(1)); // } // // This eager conversion helps with a simple case like this, but doesn't // fully make these types work in general. For example the following still // uses a dangling reference: // // TEST(Foo, Baz) { // MockFunction()> mock; // // // Return the same vector twice, and then the empty vector // // thereafter. // auto action = Return(std::initializer_list{ // "taco", "burrito", // }); // // EXPECT_CALL(mock, Call) // .WillOnce(action) // .WillOnce(action) // .WillRepeatedly(Return(std::vector{})); // // EXPECT_THAT(mock.AsStdFunction()(), // ElementsAre("taco", "burrito")); // EXPECT_THAT(mock.AsStdFunction()(), // ElementsAre("taco", "burrito")); // EXPECT_THAT(mock.AsStdFunction()(), IsEmpty()); // } // U value; }; const std::shared_ptr state_; }; R value_; }; // A specialization of ReturnAction when R is ByMoveWrapper for some T. // // This version applies the type system-defeating hack of moving from T even in // the const call operator, checking at runtime that it isn't called more than // once, since the user has declared their intent to do so by using ByMove. template class ReturnAction> final { public: explicit ReturnAction(ByMoveWrapper wrapper) : state_(new State(std::move(wrapper.payload))) {} T operator()() const { GTEST_CHECK_(!state_->called) << "A ByMove() action must be performed at most once."; state_->called = true; return std::move(state_->value); } private: // We store our state on the heap so that we are copyable as required by // Action, despite the fact that we are stateful and T may not be copyable. struct State { explicit State(T&& value_in) : value(std::move(value_in)) {} T value; bool called = false; }; const std::shared_ptr state_; }; // Implements the ReturnNull() action. class ReturnNullAction { public: // Allows ReturnNull() to be used in any pointer-returning function. In C++11 // this is enforced by returning nullptr, and in non-C++11 by asserting a // pointer type on compile time. template static Result Perform(const ArgumentTuple&) { return nullptr; } }; // Implements the Return() action. class ReturnVoidAction { public: // Allows Return() to be used in any void-returning function. template static void Perform(const ArgumentTuple&) { static_assert(std::is_void::value, "Result should be void."); } }; // Implements the polymorphic ReturnRef(x) action, which can be used // in any function that returns a reference to the type of x, // regardless of the argument types. template class ReturnRefAction { public: // Constructs a ReturnRefAction object from the reference to be returned. explicit ReturnRefAction(T& ref) : ref_(ref) {} // NOLINT // This template type conversion operator allows ReturnRef(x) to be // used in ANY function that returns a reference to x's type. template operator Action() const { typedef typename Function::Result Result; // Asserts that the function return type is a reference. This // catches the user error of using ReturnRef(x) when Return(x) // should be used, and generates some helpful error message. static_assert(std::is_reference::value, "use Return instead of ReturnRef to return a value"); return Action(new Impl(ref_)); } private: // Implements the ReturnRef(x) action for a particular function type F. template class Impl : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; explicit Impl(T& ref) : ref_(ref) {} // NOLINT Result Perform(const ArgumentTuple&) override { return ref_; } private: T& ref_; }; T& ref_; }; // Implements the polymorphic ReturnRefOfCopy(x) action, which can be // used in any function that returns a reference to the type of x, // regardless of the argument types. template class ReturnRefOfCopyAction { public: // Constructs a ReturnRefOfCopyAction object from the reference to // be returned. explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT // This template type conversion operator allows ReturnRefOfCopy(x) to be // used in ANY function that returns a reference to x's type. template operator Action() const { typedef typename Function::Result Result; // Asserts that the function return type is a reference. This // catches the user error of using ReturnRefOfCopy(x) when Return(x) // should be used, and generates some helpful error message. static_assert(std::is_reference::value, "use Return instead of ReturnRefOfCopy to return a value"); return Action(new Impl(value_)); } private: // Implements the ReturnRefOfCopy(x) action for a particular function type F. template class Impl : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; explicit Impl(const T& value) : value_(value) {} // NOLINT Result Perform(const ArgumentTuple&) override { return value_; } private: T value_; }; const T value_; }; // Implements the polymorphic ReturnRoundRobin(v) action, which can be // used in any function that returns the element_type of v. template class ReturnRoundRobinAction { public: explicit ReturnRoundRobinAction(std::vector values) { GTEST_CHECK_(!values.empty()) << "ReturnRoundRobin requires at least one element."; state_->values = std::move(values); } template T operator()(Args&&...) const { return state_->Next(); } private: struct State { T Next() { T ret_val = values[i++]; if (i == values.size()) i = 0; return ret_val; } std::vector values; size_t i = 0; }; std::shared_ptr state_ = std::make_shared(); }; // Implements the polymorphic DoDefault() action. class DoDefaultAction { public: // This template type conversion operator allows DoDefault() to be // used in any function. template operator Action() const { return Action(); } // NOLINT }; // Implements the Assign action to set a given pointer referent to a // particular value. template class AssignAction { public: AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {} template void Perform(const ArgumentTuple& /* args */) const { *ptr_ = value_; } private: T1* const ptr_; const T2 value_; }; #ifndef GTEST_OS_WINDOWS_MOBILE // Implements the SetErrnoAndReturn action to simulate return from // various system calls and libc functions. template class SetErrnoAndReturnAction { public: SetErrnoAndReturnAction(int errno_value, T result) : errno_(errno_value), result_(result) {} template Result Perform(const ArgumentTuple& /* args */) const { errno = errno_; return result_; } private: const int errno_; const T result_; }; #endif // !GTEST_OS_WINDOWS_MOBILE // Implements the SetArgumentPointee(x) action for any function // whose N-th argument (0-based) is a pointer to x's type. template struct SetArgumentPointeeAction { A value; template void operator()(const Args&... args) const { *::std::get(std::tie(args...)) = value; } }; // Implements the Invoke(object_ptr, &Class::Method) action. template struct InvokeMethodAction { Class* const obj_ptr; const MethodPtr method_ptr; template auto operator()(Args&&... args) const -> decltype((obj_ptr->*method_ptr)(std::forward(args)...)) { return (obj_ptr->*method_ptr)(std::forward(args)...); } }; // Implements the InvokeWithoutArgs(f) action. The template argument // FunctionImpl is the implementation type of f, which can be either a // function pointer or a functor. InvokeWithoutArgs(f) can be used as an // Action as long as f's type is compatible with F. template struct InvokeWithoutArgsAction { FunctionImpl function_impl; // Allows InvokeWithoutArgs(f) to be used as any action whose type is // compatible with f. template auto operator()(const Args&...) -> decltype(function_impl()) { return function_impl(); } }; // Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action. template struct InvokeMethodWithoutArgsAction { Class* const obj_ptr; const MethodPtr method_ptr; using ReturnType = decltype((std::declval()->*std::declval())()); template ReturnType operator()(const Args&...) const { return (obj_ptr->*method_ptr)(); } }; // Implements the IgnoreResult(action) action. template class IgnoreResultAction { public: explicit IgnoreResultAction(const A& action) : action_(action) {} template operator Action() const { // Assert statement belongs here because this is the best place to verify // conditions on F. It produces the clearest error messages // in most compilers. // Impl really belongs in this scope as a local class but can't // because MSVC produces duplicate symbols in different translation units // in this case. Until MS fixes that bug we put Impl into the class scope // and put the typedef both here (for use in assert statement) and // in the Impl class. But both definitions must be the same. typedef typename internal::Function::Result Result; // Asserts at compile time that F returns void. static_assert(std::is_void::value, "Result type should be void."); return Action(new Impl(action_)); } private: template class Impl : public ActionInterface { public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; explicit Impl(const A& action) : action_(action) {} void Perform(const ArgumentTuple& args) override { // Performs the action and ignores its result. action_.Perform(args); } private: // Type OriginalFunction is the same as F except that its return // type is IgnoredValue. typedef typename internal::Function::MakeResultIgnoredValue OriginalFunction; const Action action_; }; const A action_; }; template struct WithArgsAction { InnerAction inner_action; // The signature of the function as seen by the inner action, given an out // action with the given result and argument types. template using InnerSignature = R(typename std::tuple_element>::type...); // Rather than a call operator, we must define conversion operators to // particular action types. This is necessary for embedded actions like // DoDefault(), which rely on an action conversion operators rather than // providing a call operator because even with a particular set of arguments // they don't have a fixed return type. template < typename R, typename... Args, typename std::enable_if< std::is_convertible>...)>>::value, int>::type = 0> operator OnceAction() && { // NOLINT struct OA { OnceAction> inner_action; R operator()(Args&&... args) && { return std::move(inner_action) .Call(std::get( std::forward_as_tuple(std::forward(args)...))...); } }; return OA{std::move(inner_action)}; } // As above, but in the case where we want to create a OnceAction from a const // WithArgsAction. This is fine as long as the inner action doesn't need to // move any of its state to create a OnceAction. template < typename R, typename... Args, typename std::enable_if< std::is_convertible>...)>>::value, int>::type = 0> operator OnceAction() const& { // NOLINT struct OA { OnceAction> inner_action; R operator()(Args&&... args) && { return std::move(inner_action) .Call(std::get( std::forward_as_tuple(std::forward(args)...))...); } }; return OA{inner_action}; } template < typename R, typename... Args, typename std::enable_if< std::is_convertible>...)>>::value, int>::type = 0> operator Action() const { // NOLINT Action> converted(inner_action); return [converted](Args&&... args) -> R { return converted.Perform(std::forward_as_tuple( std::get(std::forward_as_tuple(std::forward(args)...))...)); }; } }; template class DoAllAction; // Base case: only a single action. template class DoAllAction { public: struct UserConstructorTag {}; template explicit DoAllAction(UserConstructorTag, T&& action) : final_action_(std::forward(action)) {} // Rather than a call operator, we must define conversion operators to // particular action types. This is necessary for embedded actions like // DoDefault(), which rely on an action conversion operators rather than // providing a call operator because even with a particular set of arguments // they don't have a fixed return type. // We support conversion to OnceAction whenever the sub-action does. template >::value, int>::type = 0> operator OnceAction() && { // NOLINT return std::move(final_action_); } // We also support conversion to OnceAction whenever the sub-action supports // conversion to Action (since any Action can also be a OnceAction). template < typename R, typename... Args, typename std::enable_if< conjunction< negation< std::is_convertible>>, std::is_convertible>>::value, int>::type = 0> operator OnceAction() && { // NOLINT return Action(std::move(final_action_)); } // We support conversion to Action whenever the sub-action does. template < typename R, typename... Args, typename std::enable_if< std::is_convertible>::value, int>::type = 0> operator Action() const { // NOLINT return final_action_; } private: FinalAction final_action_; }; // Recursive case: support N actions by calling the initial action and then // calling through to the base class containing N-1 actions. template class DoAllAction : private DoAllAction { private: using Base = DoAllAction; // The type of reference that should be provided to an initial action for a // mocked function parameter of type T. // // There are two quirks here: // // * Unlike most forwarding functions, we pass scalars through by value. // This isn't strictly necessary because an lvalue reference would work // fine too and be consistent with other non-reference types, but it's // perhaps less surprising. // // For example if the mocked function has signature void(int), then it // might seem surprising for the user's initial action to need to be // convertible to Action. This is perhaps less // surprising for a non-scalar type where there may be a performance // impact, or it might even be impossible, to pass by value. // // * More surprisingly, `const T&` is often not a const reference type. // By the reference collapsing rules in C++17 [dcl.ref]/6, if T refers to // U& or U&& for some non-scalar type U, then InitialActionArgType is // U&. In other words, we may hand over a non-const reference. // // So for example, given some non-scalar type Obj we have the following // mappings: // // T InitialActionArgType // ------- ----------------------- // Obj const Obj& // Obj& Obj& // Obj&& Obj& // const Obj const Obj& // const Obj& const Obj& // const Obj&& const Obj& // // In other words, the initial actions get a mutable view of an non-scalar // argument if and only if the mock function itself accepts a non-const // reference type. They are never given an rvalue reference to an // non-scalar type. // // This situation makes sense if you imagine use with a matcher that is // designed to write through a reference. For example, if the caller wants // to fill in a reference argument and then return a canned value: // // EXPECT_CALL(mock, Call) // .WillOnce(DoAll(SetArgReferee<0>(17), Return(19))); // template using InitialActionArgType = typename std::conditional::value, T, const T&>::type; public: struct UserConstructorTag {}; template explicit DoAllAction(UserConstructorTag, T&& initial_action, U&&... other_actions) : Base({}, std::forward(other_actions)...), initial_action_(std::forward(initial_action)) {} // We support conversion to OnceAction whenever both the initial action and // the rest support conversion to OnceAction. template < typename R, typename... Args, typename std::enable_if< conjunction...)>>, std::is_convertible>>::value, int>::type = 0> operator OnceAction() && { // NOLINT // Return an action that first calls the initial action with arguments // filtered through InitialActionArgType, then forwards arguments directly // to the base class to deal with the remaining actions. struct OA { OnceAction...)> initial_action; OnceAction remaining_actions; R operator()(Args... args) && { std::move(initial_action) .Call(static_cast>(args)...); return std::move(remaining_actions).Call(std::forward(args)...); } }; return OA{ std::move(initial_action_), std::move(static_cast(*this)), }; } // We also support conversion to OnceAction whenever the initial action // supports conversion to Action (since any Action can also be a OnceAction). // // The remaining sub-actions must also be compatible, but we don't need to // special case them because the base class deals with them. template < typename R, typename... Args, typename std::enable_if< conjunction< negation...)>>>, std::is_convertible...)>>, std::is_convertible>>::value, int>::type = 0> operator OnceAction() && { // NOLINT return DoAll( Action...)>(std::move(initial_action_)), std::move(static_cast(*this))); } // We support conversion to Action whenever both the initial action and the // rest support conversion to Action. template < typename R, typename... Args, typename std::enable_if< conjunction< std::is_convertible...)>>, std::is_convertible>>::value, int>::type = 0> operator Action() const { // NOLINT // Return an action that first calls the initial action with arguments // filtered through InitialActionArgType, then forwards arguments directly // to the base class to deal with the remaining actions. struct OA { Action...)> initial_action; Action remaining_actions; R operator()(Args... args) const { initial_action.Perform(std::forward_as_tuple( static_cast>(args)...)); return remaining_actions.Perform( std::forward_as_tuple(std::forward(args)...)); } }; return OA{ initial_action_, static_cast(*this), }; } private: InitialAction initial_action_; }; template struct ReturnNewAction { T* operator()() const { return internal::Apply( [](const Params&... unpacked_params) { return new T(unpacked_params...); }, params); } std::tuple params; }; template struct ReturnArgAction { template ::type> auto operator()(Args&&... args) const -> decltype(std::get( std::forward_as_tuple(std::forward(args)...))) { return std::get(std::forward_as_tuple(std::forward(args)...)); } }; template struct SaveArgAction { Ptr pointer; template void operator()(const Args&... args) const { *pointer = std::get(std::tie(args...)); } }; template struct SaveArgByMoveAction { Ptr pointer; template void operator()(Args&&... args) const { *pointer = std::move(std::get(std::tie(args...))); } }; template struct SaveArgPointeeAction { Ptr pointer; template void operator()(const Args&... args) const { *pointer = *std::get(std::tie(args...)); } }; template struct SetArgRefereeAction { T value; template void operator()(Args&&... args) const { using argk_type = typename ::std::tuple_element>::type; static_assert(std::is_lvalue_reference::value, "Argument must be a reference type."); std::get(std::tie(args...)) = value; } }; template struct SetArrayArgumentAction { I1 first; I2 last; template void operator()(const Args&... args) const { auto value = std::get(std::tie(args...)); for (auto it = first; it != last; ++it, (void)++value) { *value = *it; } } }; template struct DeleteArgAction { template void operator()(const Args&... args) const { delete std::get(std::tie(args...)); } }; template struct ReturnPointeeAction { Ptr pointer; template auto operator()(const Args&...) const -> decltype(*pointer) { return *pointer; } }; #if GTEST_HAS_EXCEPTIONS template struct ThrowAction { T exception; // We use a conversion operator to adapt to any return type. template operator Action() const { // NOLINT T copy = exception; return [copy](Args...) -> R { throw copy; }; } }; struct RethrowAction { std::exception_ptr exception; template operator Action() const { // NOLINT return [ex = exception](Args...) -> R { std::rethrow_exception(ex); }; } }; #endif // GTEST_HAS_EXCEPTIONS } // namespace internal // An Unused object can be implicitly constructed from ANY value. // This is handy when defining actions that ignore some or all of the // mock function arguments. For example, given // // MOCK_METHOD3(Foo, double(const string& label, double x, double y)); // MOCK_METHOD3(Bar, double(int index, double x, double y)); // // instead of // // double DistanceToOriginWithLabel(const string& label, double x, double y) { // return sqrt(x*x + y*y); // } // double DistanceToOriginWithIndex(int index, double x, double y) { // return sqrt(x*x + y*y); // } // ... // EXPECT_CALL(mock, Foo("abc", _, _)) // .WillOnce(Invoke(DistanceToOriginWithLabel)); // EXPECT_CALL(mock, Bar(5, _, _)) // .WillOnce(Invoke(DistanceToOriginWithIndex)); // // you could write // // // We can declare any uninteresting argument as Unused. // double DistanceToOrigin(Unused, double x, double y) { // return sqrt(x*x + y*y); // } // ... // EXPECT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); // EXPECT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); typedef internal::IgnoredValue Unused; // Deprecated single-argument DoAll. template GMOCK_DEPRECATE_AND_INLINE() typename std::decay::type DoAll(Action&& action) { return std::forward(action); } // Creates an action that does actions a1, a2, ..., sequentially in // each invocation. All but the last action will have a readonly view of the // arguments. template internal::DoAllAction::type...> DoAll( Action&&... action) { return internal::DoAllAction::type...>( {}, std::forward(action)...); } // WithArg(an_action) creates an action that passes the k-th // (0-based) argument of the mock function to an_action and performs // it. It adapts an action accepting one argument to one that accepts // multiple arguments. For convenience, we also provide // WithArgs(an_action) (defined below) as a synonym. template internal::WithArgsAction::type, k> WithArg( InnerAction&& action) { return {std::forward(action)}; } // WithArgs(an_action) creates an action that passes // the selected arguments of the mock function to an_action and // performs it. It serves as an adaptor between actions with // different argument lists. template internal::WithArgsAction::type, k, ks...> WithArgs(InnerAction&& action) { return {std::forward(action)}; } // WithoutArgs(inner_action) can be used in a mock function with a // non-empty argument list to perform inner_action, which takes no // argument. In other words, it adapts an action accepting no // argument to one that accepts (and ignores) arguments. template internal::WithArgsAction::type> WithoutArgs( InnerAction&& action) { return {std::forward(action)}; } // Creates an action that returns a value. // // The returned type can be used with a mock function returning a non-void, // non-reference type U as follows: // // * If R is convertible to U and U is move-constructible, then the action can // be used with WillOnce. // // * If const R& is convertible to U and U is copy-constructible, then the // action can be used with both WillOnce and WillRepeatedly. // // The mock expectation contains the R value from which the U return value is // constructed (a move/copy of the argument to Return). This means that the R // value will survive at least until the mock object's expectations are cleared // or the mock object is destroyed, meaning that U can safely be a // reference-like type such as std::string_view: // // // The mock function returns a view of a copy of the string fed to // // Return. The view is valid even after the action is performed. // MockFunction mock; // EXPECT_CALL(mock, Call).WillOnce(Return(std::string("taco"))); // const std::string_view result = mock.AsStdFunction()(); // EXPECT_EQ("taco", result); // template internal::ReturnAction Return(R value) { return internal::ReturnAction(std::move(value)); } // Creates an action that returns NULL. inline PolymorphicAction ReturnNull() { return MakePolymorphicAction(internal::ReturnNullAction()); } // Creates an action that returns from a void function. inline PolymorphicAction Return() { return MakePolymorphicAction(internal::ReturnVoidAction()); } // Creates an action that returns the reference to a variable. template inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT return internal::ReturnRefAction(x); } // Prevent using ReturnRef on reference to temporary. template internal::ReturnRefAction ReturnRef(R&&) = delete; // Creates an action that returns the reference to a copy of the // argument. The copy is created when the action is constructed and // lives as long as the action. template inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { return internal::ReturnRefOfCopyAction(x); } // DEPRECATED: use Return(x) directly with WillOnce. // // Modifies the parent action (a Return() action) to perform a move of the // argument instead of a copy. // Return(ByMove()) actions can only be executed once and will assert this // invariant. template internal::ByMoveWrapper ByMove(R x) { return internal::ByMoveWrapper(std::move(x)); } // Creates an action that returns an element of `vals`. Calling this action will // repeatedly return the next value from `vals` until it reaches the end and // will restart from the beginning. template internal::ReturnRoundRobinAction ReturnRoundRobin(std::vector vals) { return internal::ReturnRoundRobinAction(std::move(vals)); } // Creates an action that returns an element of `vals`. Calling this action will // repeatedly return the next value from `vals` until it reaches the end and // will restart from the beginning. template internal::ReturnRoundRobinAction ReturnRoundRobin( std::initializer_list vals) { return internal::ReturnRoundRobinAction(std::vector(vals)); } // Creates an action that does the default action for the give mock function. inline internal::DoDefaultAction DoDefault() { return internal::DoDefaultAction(); } // Creates an action that sets the variable pointed by the N-th // (0-based) function argument to 'value'. template internal::SetArgumentPointeeAction SetArgPointee(T value) { return {std::move(value)}; } // The following version is DEPRECATED. template internal::SetArgumentPointeeAction SetArgumentPointee(T value) { return {std::move(value)}; } // Creates an action that sets a pointer referent to a given value. template PolymorphicAction> Assign(T1* ptr, T2 val) { return MakePolymorphicAction(internal::AssignAction(ptr, val)); } #ifndef GTEST_OS_WINDOWS_MOBILE // Creates an action that sets errno and returns the appropriate error. template PolymorphicAction> SetErrnoAndReturn( int errval, T result) { return MakePolymorphicAction( internal::SetErrnoAndReturnAction(errval, result)); } #endif // !GTEST_OS_WINDOWS_MOBILE // Various overloads for Invoke(). // Legacy function. // Actions can now be implicitly constructed from callables. No need to create // wrapper objects. // This function exists for backwards compatibility. template GMOCK_DEPRECATE_AND_INLINE() typename std::decay::type Invoke(FunctionImpl&& function_impl) { return std::forward(function_impl); } // Creates an action that invokes the given method on the given object // with the mock function's arguments. template internal::InvokeMethodAction Invoke(Class* obj_ptr, MethodPtr method_ptr) { return {obj_ptr, method_ptr}; } // Creates an action that invokes 'function_impl' with no argument. template internal::InvokeWithoutArgsAction::type> InvokeWithoutArgs(FunctionImpl function_impl) { return {std::move(function_impl)}; } // Creates an action that invokes the given method on the given object // with no argument. template internal::InvokeMethodWithoutArgsAction InvokeWithoutArgs( Class* obj_ptr, MethodPtr method_ptr) { return {obj_ptr, method_ptr}; } // Creates an action that performs an_action and throws away its // result. In other words, it changes the return type of an_action to // void. an_action MUST NOT return void, or the code won't compile. template inline internal::IgnoreResultAction IgnoreResult(const A& an_action) { return internal::IgnoreResultAction(an_action); } // Creates a reference wrapper for the given L-value. If necessary, // you can explicitly specify the type of the reference. For example, // suppose 'derived' is an object of type Derived, ByRef(derived) // would wrap a Derived&. If you want to wrap a const Base& instead, // where Base is a base class of Derived, just write: // // ByRef(derived) // // N.B. ByRef is redundant with std::ref, std::cref and std::reference_wrapper. // However, it may still be used for consistency with ByMove(). template inline ::std::reference_wrapper ByRef(T& l_value) { // NOLINT return ::std::reference_wrapper(l_value); } // The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new // instance of type T, constructed on the heap with constructor arguments // a1, a2, ..., and a_k. The caller assumes ownership of the returned value. template internal::ReturnNewAction::type...> ReturnNew( Params&&... params) { return {std::forward_as_tuple(std::forward(params)...)}; } // Action ReturnArg() returns the k-th argument of the mock function. template internal::ReturnArgAction ReturnArg() { return {}; } // Action SaveArg(pointer) saves the k-th (0-based) argument of the // mock function to *pointer. template internal::SaveArgAction SaveArg(Ptr pointer) { return {pointer}; } // Action SaveArgByMove(pointer) moves the k-th (0-based) argument of the // mock function into *pointer. template internal::SaveArgByMoveAction SaveArgByMove(Ptr pointer) { return {pointer}; } // Action SaveArgPointee(pointer) saves the value pointed to // by the k-th (0-based) argument of the mock function to *pointer. template internal::SaveArgPointeeAction SaveArgPointee(Ptr pointer) { return {pointer}; } // Action SetArgReferee(value) assigns 'value' to the variable // referenced by the k-th (0-based) argument of the mock function. template internal::SetArgRefereeAction::type> SetArgReferee( T&& value) { return {std::forward(value)}; } // Action SetArrayArgument(first, last) copies the elements in // source range [first, last) to the array pointed to by the k-th // (0-based) argument, which can be either a pointer or an // iterator. The action does not take ownership of the elements in the // source range. template internal::SetArrayArgumentAction SetArrayArgument(I1 first, I2 last) { return {first, last}; } // Action DeleteArg() deletes the k-th (0-based) argument of the mock // function. template internal::DeleteArgAction DeleteArg() { return {}; } // This action returns the value pointed to by 'pointer'. template internal::ReturnPointeeAction ReturnPointee(Ptr pointer) { return {pointer}; } #if GTEST_HAS_EXCEPTIONS // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown, // except for std::exception_ptr, which is likely a mistake if // thrown directly. template typename std::enable_if< !std::is_base_of::type>::value, internal::ThrowAction::type>>::type Throw(T&& exception) { return {std::forward(exception)}; } // Action Rethrow(exception_ptr) can be used in a mock function of any type // to rethrow any exception_ptr. Note that the same object is thrown each time. inline internal::RethrowAction Rethrow(std::exception_ptr exception) { return {std::move(exception)}; } #endif // GTEST_HAS_EXCEPTIONS namespace internal { // A macro from the ACTION* family (defined later in gmock-generated-actions.h) // defines an action that can be used in a mock function. Typically, // these actions only care about a subset of the arguments of the mock // function. For example, if such an action only uses the second // argument, it can be used in any mock function that takes >= 2 // arguments where the type of the second argument is compatible. // // Therefore, the action implementation must be prepared to take more // arguments than it needs. The ExcessiveArg type is used to // represent those excessive arguments. In order to keep the compiler // error messages tractable, we define it in the testing namespace // instead of testing::internal. However, this is an INTERNAL TYPE // and subject to change without notice, so a user MUST NOT USE THIS // TYPE DIRECTLY. struct ExcessiveArg {}; // Builds an implementation of an Action<> for some particular signature, using // a class defined by an ACTION* macro. template struct ActionImpl; template struct ImplBase { struct Holder { // Allows each copy of the Action<> to get to the Impl. explicit operator const Impl&() const { return *ptr; } std::shared_ptr ptr; }; using type = typename std::conditional::value, Impl, Holder>::type; }; template struct ActionImpl : ImplBase::type { using Base = typename ImplBase::type; using function_type = R(Args...); using args_type = std::tuple; ActionImpl() = default; // Only defined if appropriate for Base. explicit ActionImpl(std::shared_ptr impl) : Base{std::move(impl)} {} R operator()(Args&&... arg) const { static constexpr size_t kMaxArgs = sizeof...(Args) <= 10 ? sizeof...(Args) : 10; return Apply(std::make_index_sequence{}, std::make_index_sequence<10 - kMaxArgs>{}, args_type{std::forward(arg)...}); } template R Apply(std::index_sequence, std::index_sequence, const args_type& args) const { // Impl need not be specific to the signature of action being implemented; // only the implementing function body needs to have all of the specific // types instantiated. Up to 10 of the args that are provided by the // args_type get passed, followed by a dummy of unspecified type for the // remainder up to 10 explicit args. static constexpr ExcessiveArg kExcessArg{}; return static_cast(*this) .template gmock_PerformImpl< /*function_type=*/function_type, /*return_type=*/R, /*args_type=*/args_type, /*argN_type=*/ typename std::tuple_element::type...>( /*args=*/args, std::get(args)..., ((void)excess_id, kExcessArg)...); } }; // Stores a default-constructed Impl as part of the Action<>'s // std::function<>. The Impl should be trivial to copy. template ::testing::Action MakeAction() { return ::testing::Action(ActionImpl()); } // Stores just the one given instance of Impl. template ::testing::Action MakeAction(std::shared_ptr impl) { return ::testing::Action(ActionImpl(std::move(impl))); } #define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \ , [[maybe_unused]] const arg##i##_type& arg##i #define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \ [[maybe_unused]] const args_type& args GMOCK_PP_REPEAT( \ GMOCK_INTERNAL_ARG_UNUSED, , 10) #define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i #define GMOCK_ACTION_ARG_TYPES_AND_NAMES_ \ const args_type& args GMOCK_PP_REPEAT(GMOCK_INTERNAL_ARG, , 10) #define GMOCK_INTERNAL_TEMPLATE_ARG(i, data, el) , typename arg##i##_type #define GMOCK_ACTION_TEMPLATE_ARGS_NAMES_ \ GMOCK_PP_TAIL(GMOCK_PP_REPEAT(GMOCK_INTERNAL_TEMPLATE_ARG, , 10)) #define GMOCK_INTERNAL_TYPENAME_PARAM(i, data, param) , typename param##_type #define GMOCK_ACTION_TYPENAME_PARAMS_(params) \ GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPENAME_PARAM, , params)) #define GMOCK_INTERNAL_TYPE_PARAM(i, data, param) , param##_type #define GMOCK_ACTION_TYPE_PARAMS_(params) \ GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_PARAM, , params)) #define GMOCK_INTERNAL_TYPE_GVALUE_PARAM(i, data, param) \ , param##_type gmock_p##i #define GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params) \ GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_GVALUE_PARAM, , params)) #define GMOCK_INTERNAL_GVALUE_PARAM(i, data, param) \ , std::forward(gmock_p##i) #define GMOCK_ACTION_GVALUE_PARAMS_(params) \ GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GVALUE_PARAM, , params)) #define GMOCK_INTERNAL_INIT_PARAM(i, data, param) \ , param(::std::forward(gmock_p##i)) #define GMOCK_ACTION_INIT_PARAMS_(params) \ GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_INIT_PARAM, , params)) #define GMOCK_INTERNAL_FIELD_PARAM(i, data, param) param##_type param; #define GMOCK_ACTION_FIELD_PARAMS_(params) \ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_FIELD_PARAM, , params) #define GMOCK_INTERNAL_ACTION(name, full_name, params) \ template \ class full_name { \ public: \ explicit full_name(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ : impl_(std::make_shared( \ GMOCK_ACTION_GVALUE_PARAMS_(params))) {} \ full_name(const full_name&) = default; \ full_name(full_name&&) noexcept = default; \ template \ operator ::testing::Action() const { \ return ::testing::internal::MakeAction(impl_); \ } \ \ private: \ class gmock_Impl { \ public: \ explicit gmock_Impl(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ : GMOCK_ACTION_INIT_PARAMS_(params) {} \ template \ return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ GMOCK_ACTION_FIELD_PARAMS_(params) \ }; \ std::shared_ptr impl_; \ }; \ template \ [[nodiscard]] inline full_name name( \ GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)); \ template \ inline full_name name( \ GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) { \ return full_name( \ GMOCK_ACTION_GVALUE_PARAMS_(params)); \ } \ template \ template \ return_type \ full_name::gmock_Impl::gmock_PerformImpl( \ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const } // namespace internal // Similar to GMOCK_INTERNAL_ACTION, but no bound parameters are stored. #define ACTION(name) \ class name##Action { \ public: \ explicit name##Action() noexcept {} \ name##Action(const name##Action&) noexcept {} \ template \ operator ::testing::Action() const { \ return ::testing::internal::MakeAction(); \ } \ \ private: \ class gmock_Impl { \ public: \ template \ return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ }; \ }; \ [[nodiscard]] inline name##Action name(); \ inline name##Action name() { return name##Action(); } \ template \ return_type name##Action::gmock_Impl::gmock_PerformImpl( \ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP, (__VA_ARGS__)) #define ACTION_P2(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP2, (__VA_ARGS__)) #define ACTION_P3(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP3, (__VA_ARGS__)) #define ACTION_P4(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP4, (__VA_ARGS__)) #define ACTION_P5(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP5, (__VA_ARGS__)) #define ACTION_P6(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP6, (__VA_ARGS__)) #define ACTION_P7(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP7, (__VA_ARGS__)) #define ACTION_P8(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP8, (__VA_ARGS__)) #define ACTION_P9(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP9, (__VA_ARGS__)) #define ACTION_P10(name, ...) \ GMOCK_INTERNAL_ACTION(name, name##ActionP10, (__VA_ARGS__)) } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4100 #endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ gperftools-gperftools-2.18/vendor/googletest/googlemock/include/gmock/gmock-cardinalities.h000066400000000000000000000137461513545575200324450ustar00rootroot00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Google Mock - a framework for writing C++ mock classes. // // This file implements some commonly used cardinalities. More // cardinalities can be defined by the user implementing the // CardinalityInterface interface if necessary. // IWYU pragma: private, include "gmock/gmock.h" // IWYU pragma: friend gmock/.* #ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ #define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ #include #include #include // NOLINT #include "gmock/internal/gmock-port.h" #include "gtest/gtest.h" GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) namespace testing { // To implement a cardinality Foo, define: // 1. a class FooCardinality that implements the // CardinalityInterface interface, and // 2. a factory function that creates a Cardinality object from a // const FooCardinality*. // // The two-level delegation design follows that of Matcher, providing // consistency for extension developers. It also eases ownership // management as Cardinality objects can now be copied like plain values. // The implementation of a cardinality. class CardinalityInterface { public: virtual ~CardinalityInterface() = default; // Conservative estimate on the lower/upper bound of the number of // calls allowed. virtual int ConservativeLowerBound() const { return 0; } virtual int ConservativeUpperBound() const { return INT_MAX; } // Returns true if and only if call_count calls will satisfy this // cardinality. virtual bool IsSatisfiedByCallCount(int call_count) const = 0; // Returns true if and only if call_count calls will saturate this // cardinality. virtual bool IsSaturatedByCallCount(int call_count) const = 0; // Describes self to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; }; // A Cardinality is a copyable and IMMUTABLE (except by assignment) // object that specifies how many times a mock function is expected to // be called. The implementation of Cardinality is just a std::shared_ptr // to const CardinalityInterface. Don't inherit from Cardinality! class GTEST_API_ Cardinality { public: // Constructs a null cardinality. Needed for storing Cardinality // objects in STL containers. Cardinality() = default; // Constructs a Cardinality from its implementation. explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {} // Conservative estimate on the lower/upper bound of the number of // calls allowed. int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); } int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); } // Returns true if and only if call_count calls will satisfy this // cardinality. bool IsSatisfiedByCallCount(int call_count) const { return impl_->IsSatisfiedByCallCount(call_count); } // Returns true if and only if call_count calls will saturate this // cardinality. bool IsSaturatedByCallCount(int call_count) const { return impl_->IsSaturatedByCallCount(call_count); } // Returns true if and only if call_count calls will over-saturate this // cardinality, i.e. exceed the maximum number of allowed calls. bool IsOverSaturatedByCallCount(int call_count) const { return impl_->IsSaturatedByCallCount(call_count) && !impl_->IsSatisfiedByCallCount(call_count); } // Describes self to an ostream void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } // Describes the given actual call count to an ostream. static void DescribeActualCallCountTo(int actual_call_count, ::std::ostream* os); private: std::shared_ptr impl_; }; // Creates a cardinality that allows at least n calls. GTEST_API_ Cardinality AtLeast(int n); // Creates a cardinality that allows at most n calls. GTEST_API_ Cardinality AtMost(int n); // Creates a cardinality that allows any number of calls. GTEST_API_ Cardinality AnyNumber(); // Creates a cardinality that allows between min and max calls. GTEST_API_ Cardinality Between(int min, int max); // Creates a cardinality that allows exactly n calls. GTEST_API_ Cardinality Exactly(int n); // Creates a cardinality from its implementation. inline Cardinality MakeCardinality(const CardinalityInterface* c) { return Cardinality(c); } } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ gperftools-gperftools-2.18/vendor/googletest/googlemock/include/gmock/gmock-function-mocker.h000066400000000000000000000623041513545575200327270ustar00rootroot00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Google Mock - a framework for writing C++ mock classes. // // This file implements MOCK_METHOD. // IWYU pragma: private, include "gmock/gmock.h" // IWYU pragma: friend gmock/.* #ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ #define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ #include #include // IWYU pragma: keep #include // IWYU pragma: keep #include "gmock/gmock-spec-builders.h" #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-pp.h" namespace testing { namespace internal { template using identity_t = T; template struct ThisRefAdjuster { template using AdjustT = typename std::conditional< std::is_const::type>::value, typename std::conditional::value, const T&, const T&&>::type, typename std::conditional::value, T&, T&&>::type>::type; template static AdjustT Adjust(const MockType& mock) { return static_cast>(const_cast(mock)); } }; constexpr bool PrefixOf(const char* a, const char* b) { return *a == 0 || (*a == *b && internal::PrefixOf(a + 1, b + 1)); } template constexpr bool StartsWith(const char (&prefix)[N], const char (&str)[M]) { return N <= M && internal::PrefixOf(prefix, str); } template constexpr bool EndsWith(const char (&suffix)[N], const char (&str)[M]) { return N <= M && internal::PrefixOf(suffix, str + M - N); } template constexpr bool Equals(const char (&a)[N], const char (&b)[M]) { return N == M && internal::PrefixOf(a, b); } template constexpr bool ValidateSpec(const char (&spec)[N]) { return internal::Equals("const", spec) || internal::Equals("override", spec) || internal::Equals("final", spec) || internal::Equals("noexcept", spec) || (internal::StartsWith("noexcept(", spec) && internal::EndsWith(")", spec)) || internal::Equals("ref(&)", spec) || internal::Equals("ref(&&)", spec) || (internal::StartsWith("Calltype(", spec) && internal::EndsWith(")", spec)); } } // namespace internal // The style guide prohibits "using" statements in a namespace scope // inside a header file. However, the FunctionMocker class template // is meant to be defined in the ::testing namespace. The following // line is just a trick for working around a bug in MSVC 8.0, which // cannot handle it if we define FunctionMocker in ::testing. using internal::FunctionMocker; } // namespace testing #define MOCK_METHOD(...) \ GMOCK_INTERNAL_WARNING_PUSH() \ GMOCK_INTERNAL_WARNING_CLANG(ignored, "-Wunused-member-function") \ GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__) \ GMOCK_INTERNAL_WARNING_POP() #define GMOCK_INTERNAL_MOCK_METHOD_ARG_1(...) \ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) #define GMOCK_INTERNAL_MOCK_METHOD_ARG_2(...) \ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) #define GMOCK_INTERNAL_MOCK_METHOD_ARG_3(_Ret, _MethodName, _Args) \ GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, ()) #define GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, _Spec) \ GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Args); \ GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Spec); \ GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ GMOCK_PP_NARG0 _Args, GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)); \ GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ GMOCK_PP_NARG0 _Args, _MethodName, GMOCK_INTERNAL_HAS_CONST(_Spec), \ GMOCK_INTERNAL_HAS_OVERRIDE(_Spec), GMOCK_INTERNAL_HAS_FINAL(_Spec), \ GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Spec), \ GMOCK_INTERNAL_GET_CALLTYPE_SPEC(_Spec), \ GMOCK_INTERNAL_GET_REF_SPEC(_Spec), \ (GMOCK_INTERNAL_SIGNATURE(_Ret, _Args))) #define GMOCK_INTERNAL_MOCK_METHOD_ARG_5(...) \ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) #define GMOCK_INTERNAL_MOCK_METHOD_ARG_6(...) \ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) #define GMOCK_INTERNAL_MOCK_METHOD_ARG_7(...) \ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) #define GMOCK_INTERNAL_WRONG_ARITY(...) \ static_assert( \ false, \ "MOCK_METHOD must be called with 3 or 4 arguments. _Ret, " \ "_MethodName, _Args and optionally _Spec. _Args and _Spec must be " \ "enclosed in parentheses. If _Ret is a type with unprotected commas, " \ "it must also be enclosed in parentheses.") #define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple) \ static_assert( \ GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple), \ GMOCK_PP_STRINGIZE(_Tuple) " should be enclosed in parentheses.") #define GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(_N, ...) \ static_assert( \ std::is_function<__VA_ARGS__>::value, \ "Signature must be a function type, maybe return type contains " \ "unprotected comma."); \ static_assert( \ ::testing::tuple_size::ArgumentTuple>::value == _N, \ "This method does not take " GMOCK_PP_STRINGIZE( \ _N) " arguments. Parenthesize all types with unprotected commas.") #define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec) #define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness, \ _Override, _Final, _NoexceptSpec, \ _CallType, _RefSpec, _Signature) \ typename ::testing::internal::Function::Result \ GMOCK_INTERNAL_EXPAND(_CallType) \ _MethodName(GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, _Signature, _N)) \ GMOCK_PP_IF(_Constness, const, ) \ _RefSpec _NoexceptSpec GMOCK_PP_IF(_Override, override, ) \ GMOCK_PP_IF(_Final, final, ) { \ GMOCK_MOCKER_(_N, _Constness, _MethodName) \ .SetOwnerAndName(this, #_MethodName); \ return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ .Invoke(GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, _Signature, _N)); \ } \ ::testing::MockSpec gmock_##_MethodName( \ GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N)) \ GMOCK_PP_IF(_Constness, const, ) _RefSpec { \ GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this); \ return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ .With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N)); \ } \ ::testing::MockSpec gmock_##_MethodName( \ const ::testing::internal::WithoutMatchers&, \ GMOCK_PP_IF(_Constness, const, )::testing::internal::Function< \ GMOCK_PP_REMOVE_PARENS(_Signature)>*) const _RefSpec _NoexceptSpec { \ return ::testing::internal::ThisRefAdjuster::Adjust(*this) \ .gmock_##_MethodName(GMOCK_PP_REPEAT( \ GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N)); \ } \ mutable ::testing::FunctionMocker \ GMOCK_MOCKER_(_N, _Constness, _MethodName) #define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__ // Valid modifiers. #define GMOCK_INTERNAL_HAS_CONST(_Tuple) \ GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple)) #define GMOCK_INTERNAL_HAS_OVERRIDE(_Tuple) \ GMOCK_PP_HAS_COMMA( \ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_OVERRIDE, ~, _Tuple)) #define GMOCK_INTERNAL_HAS_FINAL(_Tuple) \ GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_FINAL, ~, _Tuple)) #define GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Tuple) \ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT, ~, _Tuple) #define GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT(_i, _, _elem) \ GMOCK_PP_IF( \ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)), \ _elem, ) #define GMOCK_INTERNAL_GET_CALLTYPE_SPEC(_Tuple) \ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_CALLTYPE_SPEC_IF_CALLTYPE, ~, _Tuple) #define GMOCK_INTERNAL_CALLTYPE_SPEC_IF_CALLTYPE(_i, _, _elem) \ GMOCK_PP_IF( \ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem)), \ GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) #define GMOCK_INTERNAL_GET_REF_SPEC(_Tuple) \ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_REF_SPEC_IF_REF, ~, _Tuple) #define GMOCK_INTERNAL_REF_SPEC_IF_REF(_i, _, _elem) \ GMOCK_PP_IF(GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)), \ GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) #ifdef GMOCK_INTERNAL_STRICT_SPEC_ASSERT #define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ static_assert( \ ::testing::internal::ValidateSpec(GMOCK_PP_STRINGIZE(_elem)), \ "Token \'" GMOCK_PP_STRINGIZE( \ _elem) "\' cannot be recognized as a valid specification " \ "modifier. Is a ',' missing?"); #else #define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ static_assert( \ (GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem)) + \ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) + \ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)) + \ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem))) == 1, \ GMOCK_PP_STRINGIZE( \ _elem) " cannot be recognized as a valid specification modifier."); #endif // GMOCK_INTERNAL_STRICT_SPEC_ASSERT // Modifiers implementation. #define GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem) \ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CONST_I_, _elem) #define GMOCK_INTERNAL_DETECT_CONST_I_const , #define GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem) \ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_OVERRIDE_I_, _elem) #define GMOCK_INTERNAL_DETECT_OVERRIDE_I_override , #define GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem) \ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_FINAL_I_, _elem) #define GMOCK_INTERNAL_DETECT_FINAL_I_final , #define GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem) \ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_NOEXCEPT_I_, _elem) #define GMOCK_INTERNAL_DETECT_NOEXCEPT_I_noexcept , #define GMOCK_INTERNAL_DETECT_REF(_i, _, _elem) \ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_REF_I_, _elem) #define GMOCK_INTERNAL_DETECT_REF_I_ref , #define GMOCK_INTERNAL_UNPACK_ref(x) x #define GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem) \ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CALLTYPE_I_, _elem) #define GMOCK_INTERNAL_DETECT_CALLTYPE_I_Calltype , #define GMOCK_INTERNAL_UNPACK_Calltype(...) __VA_ARGS__ // Note: The use of `identity_t` here allows _Ret to represent return types that // would normally need to be specified in a different way. For example, a method // returning a function pointer must be written as // // fn_ptr_return_t (*method(method_args_t...))(fn_ptr_args_t...) // // But we only support placing the return type at the beginning. To handle this, // we wrap all calls in identity_t, so that a declaration will be expanded to // // identity_t method(method_args_t...) // // This allows us to work around the syntactic oddities of function/method // types. #define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args) \ ::testing::internal::identity_t( \ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args)) #define GMOCK_INTERNAL_GET_TYPE(_i, _, _elem) \ GMOCK_PP_COMMA_IF(_i) \ GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_elem), GMOCK_PP_REMOVE_PARENS, \ GMOCK_PP_IDENTITY) \ (_elem) #define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _) \ GMOCK_PP_COMMA_IF(_i) \ GMOCK_INTERNAL_ARG_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ gmock_a##_i #define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _) \ GMOCK_PP_COMMA_IF(_i) \ ::std::forward(gmock_a##_i) #define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _) \ GMOCK_PP_COMMA_IF(_i) \ GMOCK_INTERNAL_MATCHER_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ gmock_a##_i #define GMOCK_INTERNAL_MATCHER_ARGUMENT(_i, _1, _2) \ GMOCK_PP_COMMA_IF(_i) \ gmock_a##_i #define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _) \ GMOCK_PP_COMMA_IF(_i) \ ::testing::A() #define GMOCK_INTERNAL_ARG_O(_i, ...) \ typename ::testing::internal::Function<__VA_ARGS__>::template Arg<_i>::type #define GMOCK_INTERNAL_MATCHER_O(_i, ...) \ const ::testing::Matcher::template Arg<_i>::type>& #define MOCK_METHOD0(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 0, __VA_ARGS__) #define MOCK_METHOD1(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 1, __VA_ARGS__) #define MOCK_METHOD2(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 2, __VA_ARGS__) #define MOCK_METHOD3(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 3, __VA_ARGS__) #define MOCK_METHOD4(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 4, __VA_ARGS__) #define MOCK_METHOD5(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 5, __VA_ARGS__) #define MOCK_METHOD6(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 6, __VA_ARGS__) #define MOCK_METHOD7(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 7, __VA_ARGS__) #define MOCK_METHOD8(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 8, __VA_ARGS__) #define MOCK_METHOD9(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 9, __VA_ARGS__) #define MOCK_METHOD10(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, , m, 10, __VA_ARGS__) #define MOCK_CONST_METHOD0(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 0, __VA_ARGS__) #define MOCK_CONST_METHOD1(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 1, __VA_ARGS__) #define MOCK_CONST_METHOD2(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 2, __VA_ARGS__) #define MOCK_CONST_METHOD3(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 3, __VA_ARGS__) #define MOCK_CONST_METHOD4(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 4, __VA_ARGS__) #define MOCK_CONST_METHOD5(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 5, __VA_ARGS__) #define MOCK_CONST_METHOD6(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 6, __VA_ARGS__) #define MOCK_CONST_METHOD7(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 7, __VA_ARGS__) #define MOCK_CONST_METHOD8(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 8, __VA_ARGS__) #define MOCK_CONST_METHOD9(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 9, __VA_ARGS__) #define MOCK_CONST_METHOD10(m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, , m, 10, __VA_ARGS__) #define MOCK_METHOD0_T(m, ...) MOCK_METHOD0(m, __VA_ARGS__) #define MOCK_METHOD1_T(m, ...) MOCK_METHOD1(m, __VA_ARGS__) #define MOCK_METHOD2_T(m, ...) MOCK_METHOD2(m, __VA_ARGS__) #define MOCK_METHOD3_T(m, ...) MOCK_METHOD3(m, __VA_ARGS__) #define MOCK_METHOD4_T(m, ...) MOCK_METHOD4(m, __VA_ARGS__) #define MOCK_METHOD5_T(m, ...) MOCK_METHOD5(m, __VA_ARGS__) #define MOCK_METHOD6_T(m, ...) MOCK_METHOD6(m, __VA_ARGS__) #define MOCK_METHOD7_T(m, ...) MOCK_METHOD7(m, __VA_ARGS__) #define MOCK_METHOD8_T(m, ...) MOCK_METHOD8(m, __VA_ARGS__) #define MOCK_METHOD9_T(m, ...) MOCK_METHOD9(m, __VA_ARGS__) #define MOCK_METHOD10_T(m, ...) MOCK_METHOD10(m, __VA_ARGS__) #define MOCK_CONST_METHOD0_T(m, ...) MOCK_CONST_METHOD0(m, __VA_ARGS__) #define MOCK_CONST_METHOD1_T(m, ...) MOCK_CONST_METHOD1(m, __VA_ARGS__) #define MOCK_CONST_METHOD2_T(m, ...) MOCK_CONST_METHOD2(m, __VA_ARGS__) #define MOCK_CONST_METHOD3_T(m, ...) MOCK_CONST_METHOD3(m, __VA_ARGS__) #define MOCK_CONST_METHOD4_T(m, ...) MOCK_CONST_METHOD4(m, __VA_ARGS__) #define MOCK_CONST_METHOD5_T(m, ...) MOCK_CONST_METHOD5(m, __VA_ARGS__) #define MOCK_CONST_METHOD6_T(m, ...) MOCK_CONST_METHOD6(m, __VA_ARGS__) #define MOCK_CONST_METHOD7_T(m, ...) MOCK_CONST_METHOD7(m, __VA_ARGS__) #define MOCK_CONST_METHOD8_T(m, ...) MOCK_CONST_METHOD8(m, __VA_ARGS__) #define MOCK_CONST_METHOD9_T(m, ...) MOCK_CONST_METHOD9(m, __VA_ARGS__) #define MOCK_CONST_METHOD10_T(m, ...) MOCK_CONST_METHOD10(m, __VA_ARGS__) #define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 0, __VA_ARGS__) #define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 1, __VA_ARGS__) #define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 2, __VA_ARGS__) #define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 3, __VA_ARGS__) #define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 4, __VA_ARGS__) #define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 5, __VA_ARGS__) #define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 6, __VA_ARGS__) #define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 7, __VA_ARGS__) #define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 8, __VA_ARGS__) #define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 9, __VA_ARGS__) #define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 10, __VA_ARGS__) #define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 0, __VA_ARGS__) #define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 1, __VA_ARGS__) #define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 2, __VA_ARGS__) #define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 3, __VA_ARGS__) #define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 4, __VA_ARGS__) #define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 5, __VA_ARGS__) #define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 6, __VA_ARGS__) #define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 7, __VA_ARGS__) #define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 8, __VA_ARGS__) #define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 9, __VA_ARGS__) #define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 10, __VA_ARGS__) #define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) #define GMOCK_INTERNAL_MOCK_METHODN(constness, ct, Method, args_num, ...) \ GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ args_num, ::testing::internal::identity_t<__VA_ARGS__>); \ GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ args_num, Method, GMOCK_PP_NARG0(constness), 0, 0, , ct, , \ (::testing::internal::identity_t<__VA_ARGS__>)) #define GMOCK_MOCKER_(arity, constness, Method) \ GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) #endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ gperftools-gperftools-2.18/vendor/googletest/googlemock/include/gmock/gmock-matchers.h000066400000000000000000006632441513545575200314440ustar00rootroot00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Google Mock - a framework for writing C++ mock classes. // // The MATCHER* family of macros can be used in a namespace scope to // define custom matchers easily. // // Basic Usage // =========== // // The syntax // // MATCHER(name, description_string) { statements; } // // defines a matcher with the given name that executes the statements, // which must return a bool to indicate if the match succeeds. Inside // the statements, you can refer to the value being matched by 'arg', // and refer to its type by 'arg_type'. // // The description string documents what the matcher does, and is used // to generate the failure message when the match fails. Since a // MATCHER() is usually defined in a header file shared by multiple // C++ source files, we require the description to be a C-string // literal to avoid possible side effects. It can be empty, in which // case we'll use the sequence of words in the matcher name as the // description. // // For example: // // MATCHER(IsEven, "") { return (arg % 2) == 0; } // // allows you to write // // // Expects mock_foo.Bar(n) to be called where n is even. // EXPECT_CALL(mock_foo, Bar(IsEven())); // // or, // // // Verifies that the value of some_expression is even. // EXPECT_THAT(some_expression, IsEven()); // // If the above assertion fails, it will print something like: // // Value of: some_expression // Expected: is even // Actual: 7 // // where the description "is even" is automatically calculated from the // matcher name IsEven. // // Argument Type // ============= // // Note that the type of the value being matched (arg_type) is // determined by the context in which you use the matcher and is // supplied to you by the compiler, so you don't need to worry about // declaring it (nor can you). This allows the matcher to be // polymorphic. For example, IsEven() can be used to match any type // where the value of "(arg % 2) == 0" can be implicitly converted to // a bool. In the "Bar(IsEven())" example above, if method Bar() // takes an int, 'arg_type' will be int; if it takes an unsigned long, // 'arg_type' will be unsigned long; and so on. // // Parameterizing Matchers // ======================= // // Sometimes you'll want to parameterize the matcher. For that you // can use another macro: // // MATCHER_P(name, param_name, description_string) { statements; } // // For example: // // MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } // // will allow you to write: // // EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); // // which may lead to this message (assuming n is 10): // // Value of: Blah("a") // Expected: has absolute value 10 // Actual: -9 // // Note that both the matcher description and its parameter are // printed, making the message human-friendly. // // In the matcher definition body, you can write 'foo_type' to // reference the type of a parameter named 'foo'. For example, in the // body of MATCHER_P(HasAbsoluteValue, value) above, you can write // 'value_type' to refer to the type of 'value'. // // We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to // support multi-parameter matchers. // // Describing Parameterized Matchers // ================================= // // The last argument to MATCHER*() is a string-typed expression. The // expression can reference all of the matcher's parameters and a // special bool-typed variable named 'negation'. When 'negation' is // false, the expression should evaluate to the matcher's description; // otherwise it should evaluate to the description of the negation of // the matcher. For example, // // using testing::PrintToString; // // MATCHER_P2(InClosedRange, low, hi, // std::string(negation ? "is not" : "is") + " in range [" + // PrintToString(low) + ", " + PrintToString(hi) + "]") { // return low <= arg && arg <= hi; // } // ... // EXPECT_THAT(3, InClosedRange(4, 6)); // EXPECT_THAT(3, Not(InClosedRange(2, 4))); // // would generate two failures that contain the text: // // Expected: is in range [4, 6] // ... // Expected: is not in range [2, 4] // // If you specify "" as the description, the failure message will // contain the sequence of words in the matcher name followed by the // parameter values printed as a tuple. For example, // // MATCHER_P2(InClosedRange, low, hi, "") { ... } // ... // EXPECT_THAT(3, InClosedRange(4, 6)); // EXPECT_THAT(3, Not(InClosedRange(2, 4))); // // would generate two failures that contain the text: // // Expected: in closed range (4, 6) // ... // Expected: not (in closed range (2, 4)) // // Types of Matcher Parameters // =========================== // // For the purpose of typing, you can view // // MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } // // as shorthand for // // template // FooMatcherPk // Foo(p1_type p1, ..., pk_type pk) { ... } // // When you write Foo(v1, ..., vk), the compiler infers the types of // the parameters v1, ..., and vk for you. If you are not happy with // the result of the type inference, you can specify the types by // explicitly instantiating the template, as in Foo(5, // false). As said earlier, you don't get to (or need to) specify // 'arg_type' as that's determined by the context in which the matcher // is used. You can assign the result of expression Foo(p1, ..., pk) // to a variable of type FooMatcherPk. This // can be useful when composing matchers. // // While you can instantiate a matcher template with reference types, // passing the parameters by pointer usually makes your code more // readable. If, however, you still want to pass a parameter by // reference, be aware that in the failure message generated by the // matcher you will see the value of the referenced object but not its // address. // // Explaining Match Results // ======================== // // Sometimes the matcher description alone isn't enough to explain why // the match has failed or succeeded. For example, when expecting a // long string, it can be very helpful to also print the diff between // the expected string and the actual one. To achieve that, you can // optionally stream additional information to a special variable // named result_listener, whose type is a pointer to class // MatchResultListener: // // MATCHER_P(EqualsLongString, str, "") { // if (arg == str) return true; // // *result_listener << "the difference: " /// << DiffStrings(str, arg); // return false; // } // // Overloading Matchers // ==================== // // You can overload matchers with different numbers of parameters: // // MATCHER_P(Blah, a, description_string1) { ... } // MATCHER_P2(Blah, a, b, description_string2) { ... } // // Caveats // ======= // // When defining a new matcher, you should also consider implementing // MatcherInterface or using MakePolymorphicMatcher(). These // approaches require more work than the MATCHER* macros, but also // give you more control on the types of the value being matched and // the matcher parameters, which may leads to better compiler error // messages when the matcher is used wrong. They also allow // overloading matchers based on parameter types (as opposed to just // based on the number of parameters). // // MATCHER*() can only be used in a namespace scope as templates cannot be // declared inside of a local class. // // More Information // ================ // // To learn more about using these macros, please search for 'MATCHER' // on // https://github.com/google/googletest/blob/main/docs/gmock_cook_book.md // // This file also implements some commonly used argument matchers. More // matchers can be defined by the user implementing the // MatcherInterface interface if necessary. // // See googletest/include/gtest/gtest-matchers.h for the definition of class // Matcher, class MatcherInterface, and others. // IWYU pragma: private, include "gmock/gmock.h" // IWYU pragma: friend gmock/.* #ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ #define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ #include #include #include #include #include #include #include #include #include #include #include // NOLINT #include #include #include #include #include #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" #include "gmock/internal/gmock-pp.h" #include "gtest/gtest.h" // MSVC warning C5046 is new as of VS2017 version 15.8. #if defined(_MSC_VER) && _MSC_VER >= 1915 #define GMOCK_MAYBE_5046_ 5046 #else #define GMOCK_MAYBE_5046_ #endif GTEST_DISABLE_MSC_WARNINGS_PUSH_( 4251 GMOCK_MAYBE_5046_ /* class A needs to have dll-interface to be used by clients of class B */ /* Symbol involving type with internal linkage not defined */) namespace testing { // To implement a matcher Foo for type T, define: // 1. a class FooMatcherImpl that implements the // MatcherInterface interface, and // 2. a factory function that creates a Matcher object from a // FooMatcherImpl*. // // The two-level delegation design makes it possible to allow a user // to write "v" instead of "Eq(v)" where a Matcher is expected, which // is impossible if we pass matchers by pointers. It also eases // ownership management as Matcher objects can now be copied like // plain values. // A match result listener that stores the explanation in a string. class StringMatchResultListener : public MatchResultListener { public: StringMatchResultListener() : MatchResultListener(&ss_) {} // Returns the explanation accumulated so far. std::string str() const { return ss_.str(); } // Clears the explanation accumulated so far. void Clear() { ss_.str(""); } private: ::std::stringstream ss_; StringMatchResultListener(const StringMatchResultListener&) = delete; StringMatchResultListener& operator=(const StringMatchResultListener&) = delete; }; // Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION // and MUST NOT BE USED IN USER CODE!!! namespace internal { // The MatcherCastImpl class template is a helper for implementing // MatcherCast(). We need this helper in order to partially // specialize the implementation of MatcherCast() (C++ allows // class/struct templates to be partially specialized, but not // function templates.). // This general version is used when MatcherCast()'s argument is a // polymorphic matcher (i.e. something that can be converted to a // Matcher but is not one yet; for example, Eq(value)) or a value (for // example, "hello"). template class MatcherCastImpl { public: static Matcher Cast(const M& polymorphic_matcher_or_value) { // M can be a polymorphic matcher, in which case we want to use // its conversion operator to create Matcher. Or it can be a value // that should be passed to the Matcher's constructor. // // We can't call Matcher(polymorphic_matcher_or_value) when M is a // polymorphic matcher because it'll be ambiguous if T has an implicit // constructor from M (this usually happens when T has an implicit // constructor from any type). // // It won't work to unconditionally implicit_cast // polymorphic_matcher_or_value to Matcher because it won't trigger // a user-defined conversion from M to T if one exists (assuming M is // a value). return CastImpl(polymorphic_matcher_or_value, std::is_convertible>{}, std::is_convertible{}); } private: template static Matcher CastImpl(const M& polymorphic_matcher_or_value, std::true_type /* convertible_to_matcher */, std::integral_constant) { // M is implicitly convertible to Matcher, which means that either // M is a polymorphic matcher or Matcher has an implicit constructor // from M. In both cases using the implicit conversion will produce a // matcher. // // Even if T has an implicit constructor from M, it won't be called because // creating Matcher would require a chain of two user-defined conversions // (first to create T from M and then to create Matcher from T). return polymorphic_matcher_or_value; } // M can't be implicitly converted to Matcher, so M isn't a polymorphic // matcher. It's a value of a type implicitly convertible to T. Use direct // initialization or `ImplicitCastEqMatcher` to create a matcher. static Matcher CastImpl(const M& value, std::false_type /* convertible_to_matcher */, std::true_type /* convertible_to_T */) { using NoRefT = std::remove_cv_t>; if constexpr (std::is_same_v) { return Matcher(value); } else { return ImplicitCastEqMatcher>(value); } } // M can't be implicitly converted to either Matcher or T. Attempt to use // polymorphic matcher Eq(value) in this case. // // Note that we first attempt to perform an implicit cast on the value and // only fall back to the polymorphic Eq() matcher afterwards because the // latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end // which might be undefined even when Rhs is implicitly convertible to Lhs // (e.g. std::pair vs. std::pair). static Matcher CastImpl(const M& value, std::false_type /* convertible_to_matcher */, std::false_type /* convertible_to_T */) { return Eq(value); } }; // This more specialized version is used when MatcherCast()'s argument // is already a Matcher. This only compiles when type T can be // statically converted to type U. template class MatcherCastImpl> { public: static Matcher Cast(const Matcher& source_matcher) { return Matcher(new Impl(source_matcher)); } private: // If it's possible to implicitly convert a `const T&` to U, then `Impl` can // take that as input to avoid a copy. Otherwise, such as when `T` is a // non-const reference type or a type explicitly constructible only from a // non-const reference, then `Impl` must use `T` as-is (potentially copying). using ImplArgT = typename std::conditional::value, const T&, T>::type; class Impl : public MatcherInterface { public: explicit Impl(const Matcher& source_matcher) : source_matcher_(source_matcher) {} // We delegate the matching logic to the source matcher. bool MatchAndExplain(ImplArgT x, MatchResultListener* listener) const override { using FromType = typename std::remove_cv::type>::type>::type; using ToType = typename std::remove_cv::type>::type>::type; // Do not allow implicitly converting base*/& to derived*/&. static_assert( // Do not trigger if only one of them is a pointer. That implies a // regular conversion and not a down_cast. (std::is_pointer::type>::value != std::is_pointer::type>::value) || std::is_same::value || !std::is_base_of::value, "Can't implicitly convert from to "); // Do the cast to `U` explicitly if necessary. // Otherwise, let implicit conversions do the trick. using CastType = typename std::conditional< std::is_convertible::value, ImplArgT&, U>::type; return source_matcher_.MatchAndExplain(static_cast(x), listener); } void DescribeTo(::std::ostream* os) const override { source_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { source_matcher_.DescribeNegationTo(os); } private: const Matcher source_matcher_; }; }; // This even more specialized version is used for efficiently casting // a matcher to its own type. template class MatcherCastImpl> { public: static Matcher Cast(const Matcher& matcher) { return matcher; } }; // Template specialization for parameterless Matcher. template class MatcherBaseImpl { public: MatcherBaseImpl() = default; template operator ::testing::Matcher() const { // NOLINT(runtime/explicit) return ::testing::Matcher(new typename Derived::template gmock_Impl()); } }; // Template specialization for Matcher with parameters. template