├── LICENSE.md ├── README.md ├── osrf_testing_tools_cpp ├── CHANGELOG.rst ├── CMakeLists.txt ├── cmake │ ├── osrf_testing_tools_cpp_add_test.cmake │ ├── osrf_testing_tools_cpp_extract_and_build_googletest.cmake │ ├── osrf_testing_tools_cpp_get_googletest_versions.cmake │ └── osrf_testing_tools_cpp_require_googletest.cmake ├── include │ └── osrf_testing_tools_cpp │ │ ├── demangle.hpp │ │ ├── macros.hpp │ │ ├── memory_tools │ │ ├── gtest_quickstart.hpp │ │ ├── initialize.hpp │ │ ├── is_working.hpp │ │ ├── memory_tools.hpp │ │ ├── memory_tools_service.hpp │ │ ├── monitoring.hpp │ │ ├── register_hooks.hpp │ │ ├── stack_trace.hpp │ │ ├── testing_helpers.hpp │ │ ├── verbosity.hpp │ │ └── visibility_control.hpp │ │ └── scope_exit.hpp ├── osrf_testing_tools_cppConfig.cmake.in ├── osrf_testing_tools_cppConfigVersion.cmake.in ├── package.xml ├── src │ ├── CMakeLists.txt │ ├── memory_tools │ │ ├── CMakeLists.txt │ │ ├── count_function_occurrences_in_backtrace.hpp │ │ ├── custom_memory_functions.cpp │ │ ├── custom_memory_functions.hpp │ │ ├── dispatch_callback.hpp │ │ ├── impl │ │ │ ├── apple.cpp │ │ │ ├── linux.cpp │ │ │ ├── static_allocator.hpp │ │ │ ├── unix_common.cpp │ │ │ ├── unix_common.hpp │ │ │ └── unsupported_os.cpp │ │ ├── implementation_monitoring_override.cpp │ │ ├── implementation_monitoring_override.hpp │ │ ├── initialize.cpp │ │ ├── is_working.cpp │ │ ├── memory_tools.cpp │ │ ├── memory_tools_service.cpp │ │ ├── memory_tools_service_factory.hpp │ │ ├── memory_tools_service_impl.hpp │ │ ├── monitoring.cpp │ │ ├── print_backtrace.hpp │ │ ├── register_hooks.cpp │ │ ├── safe_fwrite.hpp │ │ ├── stack_trace.cpp │ │ ├── stack_trace_impl.hpp │ │ ├── test_count_function_in_backtrace.cpp │ │ ├── test_lib.cpp │ │ ├── testing_helpers.cpp │ │ ├── vendor │ │ │ └── bombela │ │ │ │ └── backward-cpp │ │ │ │ ├── .clang-format │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── BackwardConfig.cmake │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── LICENSE.txt │ │ │ │ ├── README.md │ │ │ │ ├── backward.cpp │ │ │ │ ├── backward.hpp │ │ │ │ ├── builds.sh │ │ │ │ ├── conanfile.py │ │ │ │ ├── doc │ │ │ │ ├── nice.png │ │ │ │ ├── pretty.png │ │ │ │ └── rude.png │ │ │ │ ├── test │ │ │ │ ├── _test_main.cpp │ │ │ │ ├── rectrace.cpp │ │ │ │ ├── select_signals.cpp │ │ │ │ ├── stacktrace.cpp │ │ │ │ ├── suicide.cpp │ │ │ │ ├── test.cpp │ │ │ │ └── test.hpp │ │ │ │ └── test_package │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── conanfile.py │ │ │ │ └── main.cpp │ │ └── verbosity.cpp │ └── test_runner │ │ ├── CMakeLists.txt │ │ ├── execute_process.hpp │ │ ├── get_environment_variable.hpp │ │ ├── main.cpp │ │ ├── parse_environment_variable.hpp │ │ └── starts_with.hpp ├── test │ ├── CMakeLists.txt │ ├── cmake │ │ ├── CMakeLists.txt │ │ └── test_osrf_testing_tools_cpp_filter_versions.cmake │ ├── memory_tools │ │ ├── CMakeLists.txt │ │ └── test_memory_tools.cpp │ └── test_runner │ │ ├── CMakeLists.txt │ │ ├── assert_env_vars.cpp │ │ └── test_parse_environment_variable.cpp └── vendor │ └── google │ └── googletest │ ├── googletest-external-project-add.cmake.in │ └── release-1.14.0.tar.gz └── test_osrf_testing_tools_cpp ├── CHANGELOG.rst ├── CMakeLists.txt ├── package.xml └── test ├── test_example_memory_tools.cpp └── test_is_not_working.cpp /osrf_testing_tools_cpp/CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | Changelog for package osrf_testing_tools_cpp 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4 | 5 | 2.3.0 (2025-04-24) 6 | ------------------ 7 | 8 | 2.2.0 (2024-06-17) 9 | ------------------ 10 | * Update CMakeLists.txt (`#85 `_) 11 | * Contributors: mosfet80 12 | 13 | 2.1.0 (2024-04-26) 14 | ------------------ 15 | 16 | 2.0.0 (2024-02-07) 17 | ------------------ 18 | * Upgrade to Google test 1.14.0 (`#84 `_) 19 | * Contributors: Chris Lalancette 20 | 21 | 1.7.0 (2023-04-28) 22 | ------------------ 23 | 24 | 1.5.3 (2023-04-11) 25 | ------------------ 26 | * Fix mpark/variant conditional for MSVC (`#77 `_) 27 | * Changing C++ Compile Version (`#76 `_) 28 | * Update maintainers (`#74 `_) 29 | * Contributors: Audrow Nash, Lucas Wendland, Scott K Logan 30 | 31 | 1.5.2 (2022-11-07) 32 | ------------------ 33 | * Sets CMP0135 policy behavior to NEW (`#73 `_) 34 | * Fixes policy CMP0135 warning in CMake 3.24 (`#71 `_) 35 | * Add cstring include. (`#70 `_) 36 | * Contributors: Chris Lalancette, Cristóbal Arroyo 37 | 38 | 1.5.1 (2022-02-14) 39 | ------------------ 40 | * Changed to use ``CMAKE_DL_LIBS`` CMake library to link library that provides dlopen (`#68 `_) 41 | * Contributors: Silvio Traversaro 42 | 43 | 1.5.0 (2022-01-14) 44 | ------------------ 45 | * Update backward-cpp to latest master commit (`#64 `_) 46 | * Patch googletest to 1.10.0.2 (`#65 `_) 47 | * Contributors: Christophe Bedard, Homalozoa X 48 | 49 | 1.4.0 (2020-12-08) 50 | ------------------ 51 | * [osrf_testing_tools_cpp] Add warnings (`#54 `_) 52 | * Update cmake minimum version to 2.8.12 (`#61 `_) 53 | * Add googletest v1.10.0 (`#55 `_) 54 | * Workarounds for Android (`#52 `_) (`#60 `_) 55 | * Change `WIN32` to `_WIN32` (`#53 `_) 56 | * fix execinfo.h not found for QNX (`#50 `_) 57 | * Contributors: Ahmed Sobhy, Audrow Nash, Dan Rose, Jacob Perron, Stephen Brawner 58 | 59 | 1.3.2 (2020-05-21) 60 | ------------------ 61 | * Suppressed a FPHSA CMake warning in Backward (`#48 `_) 62 | * Contributors: Dirk Thomas 63 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(osrf_testing_tools_cpp) 4 | 5 | set(osrf_testing_tools_cpp_VERSION 1.5.1) 6 | 7 | # Default to C++17 8 | if(NOT CMAKE_CXX_STANDARD) 9 | set(CMAKE_CXX_STANDARD 17) 10 | endif() 11 | 12 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 13 | add_compile_options(-Wall -Wextra -Wpedantic 14 | -Wformat=2 -Wconversion -Woverloaded-virtual 15 | -Wshadow -Wnon-virtual-dtor) 16 | endif() 17 | 18 | add_subdirectory(src) 19 | 20 | include(CTest) 21 | if(BUILD_TESTING) 22 | include(cmake/osrf_testing_tools_cpp_require_googletest.cmake) 23 | # ensures target gtest_main exists 24 | osrf_testing_tools_cpp_require_googletest(VERSION_GTE 1.14 25 | VENDOR_DIR "${CMAKE_SOURCE_DIR}/vendor") 26 | 27 | add_subdirectory(test) 28 | endif() 29 | 30 | configure_file(osrf_testing_tools_cppConfig.cmake.in 31 | "${PROJECT_BINARY_DIR}/osrf_testing_tools_cppConfig.cmake" @ONLY) 32 | configure_file(osrf_testing_tools_cppConfigVersion.cmake.in 33 | "${PROJECT_BINARY_DIR}/osrf_testing_tools_cppConfigVersion.cmake" @ONLY) 34 | 35 | install(FILES 36 | "${PROJECT_BINARY_DIR}/osrf_testing_tools_cppConfig.cmake" 37 | "${PROJECT_BINARY_DIR}/osrf_testing_tools_cppConfigVersion.cmake" 38 | DESTINATION share/${PROJECT_NAME}/cmake 39 | ) 40 | 41 | install(DIRECTORY vendor/ 42 | DESTINATION share/${PROJECT_NAME}/vendor 43 | PATTERN ".gitattributes" EXCLUDE 44 | ) 45 | 46 | install(DIRECTORY cmake/ 47 | DESTINATION share/${PROJECT_NAME}/cmake 48 | ) 49 | 50 | install( 51 | DIRECTORY include/ 52 | DESTINATION include 53 | ) 54 | 55 | install(FILES 56 | package.xml 57 | DESTINATION share/${PROJECT_NAME}) 58 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/cmake/osrf_testing_tools_cpp_add_test.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # 16 | # Add a test to ctest. 17 | # 18 | # This macro will add the test to CTest via the `add_test()` cmake call, but 19 | # it will pass the executable and arguments through another executable which 20 | # can alter the environment variables for your test. 21 | # 22 | # :param testname: the name of the test 23 | # :type testname: string 24 | # :param COMMAND: the command including its arguments to invoke 25 | # :type COMMAND: list of strings 26 | # :param TIMEOUT: the test timeout in seconds, default: 60 27 | # :type TIMEOUT: integer 28 | # :param WORKING_DIRECTORY: the working directory for invoking the 29 | # command in, default: directory of the executable 30 | # see: https://cmake.org/cmake/help/latest/prop_test/WORKING_DIRECTORY.html 31 | # :type WORKING_DIRECTORY: string 32 | # :param ENV: list of env vars to set; listed as ``VAR=value`` 33 | # :type ENV: list of strings 34 | # :param APPEND_ENV: list of env vars to append if already set, otherwise set; 35 | # listed as ``VAR=value`` 36 | # :type APPEND_ENV: list of strings 37 | # :param APPEND_LIBRARY_DIRS: list of library dirs to append to the appropriate 38 | # OS specific env var, a la LD_LIBRARY_PATH 39 | # :type APPEND_LIBRARY_DIRS: list of strings 40 | # 41 | # @public 42 | # 43 | function(osrf_testing_tools_cpp_add_test testname) 44 | cmake_parse_arguments(ARG 45 | "" 46 | "TIMEOUT;WORKING_DIRECTORY" 47 | "APPEND_ENV;APPEND_LIBRARY_DIRS;COMMAND;ENV" 48 | ${ARGN}) 49 | if(ARG_UNPARSED_ARGUMENTS) 50 | message(FATAL_ERROR "osrf_testing_tools_cpp_add_test() called with unused arguments: " 51 | "${ARG_UNPARSED_ARGUMENTS}") 52 | endif() 53 | if(NOT ARG_COMMAND) 54 | message(FATAL_ERROR 55 | "osrf_testing_tools_cpp_add_test() must be invoked with the COMMAND argument") 56 | endif() 57 | if(NOT ARG_TIMEOUT) 58 | set(ARG_TIMEOUT 60) 59 | endif() 60 | if(NOT ARG_TIMEOUT GREATER 0) 61 | message(FATAL_ERROR "osrf_testing_tools_cpp_add_test() the TIMEOUT argument must be a " 62 | "valid number and greater than zero") 63 | endif() 64 | if(ARG_WORKING_DIRECTORY) 65 | set(WORKING_DIRECTORY_ARGS WORKING_DIRECTORY "ARG_WORKING_DIRECTORY") 66 | endif() 67 | 68 | # wrap command with run_test script to ensure test result generation 69 | set(test_runner_target osrf_testing_tools_cpp::test_runner) 70 | set(cmd_wrapper "$") 71 | if(ARG_ENV) 72 | list(APPEND cmd_wrapper "--env" ${ARG_ENV}) 73 | endif() 74 | if(ARG_APPEND_LIBRARY_DIRS) 75 | if(WIN32) 76 | set(_library_dirs_env_var "PATH") 77 | elseif(APPLE) 78 | set(_library_dirs_env_var "DYLD_LIBRARY_PATH") 79 | elseif(UNIX) 80 | set(_library_dirs_env_var "LD_LIBRARY_PATH") 81 | else() 82 | message(FATAL_ERROR "Unknown platform for environment variable to find libraries") 83 | endif() 84 | foreach(_dir ${ARG_APPEND_LIBRARY_DIRS}) 85 | list(APPEND ARG_APPEND_ENV "${_library_dirs_env_var}=${_dir}") 86 | endforeach() 87 | endif() 88 | if(ARG_APPEND_ENV) 89 | list(APPEND cmd_wrapper "--append-env" ${ARG_APPEND_ENV}) 90 | endif() 91 | list(APPEND cmd_wrapper "--" ${ARG_COMMAND}) 92 | 93 | add_test( 94 | NAME "${testname}" 95 | COMMAND ${cmd_wrapper} 96 | ${WORKING_DIRECTORY_ARGS} 97 | ) 98 | set_tests_properties( 99 | "${testname}" 100 | PROPERTIES TIMEOUT ${ARG_TIMEOUT} 101 | ) 102 | endfunction() 103 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/cmake/osrf_testing_tools_cpp_extract_and_build_googletest.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Based on recommendation on how to integrate googletest into a CMake project: 16 | # https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project 17 | 18 | set(__OSRF_TESTING_TOOLS_CPP_GOOGLETEST_VERSION_BUILT) 19 | 20 | macro(osrf_testing_tools_cpp_extract_and_build_googletest 21 | GOOGLETEST_ARCHIVE_LOCATION 22 | GOOGLETEST_VERSION 23 | GOOGLETEST_MD5SUM 24 | GOOGLETEST_EXTERNAL_PROJECT_ADD_TEMPLATE 25 | ) 26 | # Make sure this only happens once 27 | if(__OSRF_TESTING_TOOLS_CPP_GOOGLETEST_VERSION_BUILT) 28 | set(error_msg "osrf_testing_tools_cpp_extract_and_build_googletest():") 29 | set(error_msg "${error_msg} Cannot build requested version '${GOOGLETEST_VERSION}'") 30 | set(error_msg "${error_msg} because version") 31 | set(error_msg "${error_msg} '${__OSRF_TESTING_TOOLS_CPP_GOOGLETEST_VERSION_BUILT}'") 32 | set(error_msg "${error_msg} has already been built.") 33 | message(FATAL_ERROR ${error_msg}) 34 | endif() 35 | set(__OSRF_TESTING_TOOLS_CPP_GOOGLETEST_VERSION_BUILT ${GOOGLETEST_VERSION}) 36 | 37 | # Extract and unpack googletest at configure time 38 | 39 | # Explicitly reset these variables otherwise configure_file will not use them 40 | set(GOOGLETEST_ARCHIVE_LOCATION ${GOOGLETEST_ARCHIVE_LOCATION}) 41 | set(GOOGLETEST_VERSION ${GOOGLETEST_VERSION}) 42 | set(GOOGLETEST_MD5SUM ${GOOGLETEST_MD5SUM}) 43 | configure_file( 44 | "${GOOGLETEST_EXTERNAL_PROJECT_ADD_TEMPLATE}" 45 | googletest-${GOOGLETEST_VERSION}-extracted/CMakeLists.txt 46 | @ONLY 47 | ) 48 | 49 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 50 | RESULT_VARIABLE result 51 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-${GOOGLETEST_VERSION}-extracted) 52 | if(result) 53 | message(FATAL_ERROR "CMake step for googletest failed: ${result}") 54 | endif() 55 | 56 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 57 | RESULT_VARIABLE result 58 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-${GOOGLETEST_VERSION}-extracted) 59 | if(result) 60 | message(FATAL_ERROR "Build step for googletest failed: ${result}") 61 | endif() 62 | 63 | # Prevent overriding the parent project's compiler/linker 64 | # settings on Windows 65 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 66 | 67 | set(__prefix googletest-${GOOGLETEST_VERSION}) 68 | if(UNIX AND NOT APPLE) 69 | # When building with asan (i.e. using colcon build --mixin asan-gcc), 70 | # asan itself provides a "fake" pthread that tricks the pthread 71 | # detection logic into thinking no link libraries are necessary 72 | # (see https://wiki.gentoo.org/wiki/AddressSanitizer/Problems#pthread_linking_issues 73 | # for some additional information). To work around that, we unconditionally 74 | # add the -pthread flag for Linux machines so it will always work 75 | link_libraries("-pthread") 76 | endif() 77 | # Add googletest directly to our build. This defines 78 | # the gtest and gtest_main targets. 79 | add_subdirectory( 80 | ${CMAKE_BINARY_DIR}/${__prefix}-extracted/${__prefix}-src 81 | ${CMAKE_BINARY_DIR}/${__prefix}-extracted/${__prefix}-build 82 | EXCLUDE_FROM_ALL 83 | ) 84 | unset(__prefix) 85 | 86 | if(WIN32) 87 | # Googletest has some known warnings as errors on newer versions of VS, see: 88 | # https://github.com/google/googletest/issues/1373 89 | # So disable offending warnings for now. 90 | if(TARGET gtest) # Only in 1.7 and not 1.8 91 | target_compile_definitions(gtest PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1) 92 | endif() 93 | if(TARGET gtest_main) 94 | target_compile_definitions(gtest_main PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1) 95 | endif() 96 | endif() 97 | 98 | # The gtest/gtest_main targets carry header search path 99 | # dependencies automatically when using CMake 2.8.11 or 100 | # later. Otherwise we have to add them here ourselves. 101 | if (CMAKE_VERSION VERSION_LESS 2.8.11) 102 | include_directories("${gtest_SOURCE_DIR}/include") 103 | endif() 104 | endmacro() 105 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/cmake/osrf_testing_tools_cpp_get_googletest_versions.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # 16 | # Get a list of googletest versions and the location of their archives. 17 | # 18 | # The list is just the set of versions provided by this package. 19 | # The archives are stored in this package's repository and are not downloaded. 20 | # 21 | # :param output_versions: name of the variable in which to store the list of versions 22 | # :type output_versions: string 23 | # :param output_locations: name of the variable in which to store the list of locations 24 | # :type output_locations: string 25 | # :param output_md5s: name of the variable in which to store the list of MD5 sums 26 | # :type output_md5s: string 27 | # 28 | # @public 29 | # 30 | macro(osrf_testing_tools_cpp_get_googletest_versions output_versions output_locations output_md5s) 31 | # Manually maintained list of googletest versions provided by this package. 32 | set(${output_versions} 33 | 1.14 34 | ) 35 | # Manually maintained list of googletest locations in this package, indexed the same as versions. 36 | # They are relative to the VENDOR_DIR, which is configurable. 37 | set(${output_locations} 38 | "google/googletest/release-1.14.0.tar.gz" 39 | ) 40 | # Manually maintained list of MD5 sums for the archives, indexed the same as the versions. 41 | set(${output_md5s} 42 | "c8340a482851ef6a3fe618a082304cfc" 43 | ) 44 | endmacro() 45 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/cmake/osrf_testing_tools_cpp_require_googletest.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | if(OSRF_TESTING_TOOLS_CPP_REQUIRE_GOOGLETEST_CMAKE__INCLUDED) 16 | return() 17 | endif() 18 | set(OSRF_TESTING_TOOLS_CPP_REQUIRE_GOOGLETEST_CMAKE__INCLUDED TRUE) 19 | 20 | include(${CMAKE_CURRENT_LIST_DIR}/osrf_testing_tools_cpp_get_googletest_versions.cmake) 21 | include(${CMAKE_CURRENT_LIST_DIR}/osrf_testing_tools_cpp_extract_and_build_googletest.cmake) 22 | set(OSRF_TESTING_TOOLS_CPP_REQUIRE_GOOGLETEST_VERSION_SETUP) 23 | 24 | # 25 | # Provides and sets up googletest at the requested version. 26 | # 27 | # This package provides several versions of googletest, the best of which will 28 | # be selected, built, and setup based on the version constraints given. 29 | # This macro should only be called once, as two googletests being built 30 | # simultaneously is not supported. 31 | # 32 | # :param VERSION_EQ: exact version to match, mutually exclusive with all other options 33 | # :type VERSION_EQ: string 34 | # :param VERSION_LT: version must be less than, mutually exclusive with VERSION_LTE 35 | # :type VERSION_LT: string 36 | # :param VERSION_LTE: version must be less than or equal, mutually exclusive with VERSION_LT 37 | # :type VERSION_LTE: string 38 | # :param VERSION_GT: version must be greater than, mutually exclusive with VERSION_GTE 39 | # :type VERSION_GT: string 40 | # :param VERSION_GTE: version must be greater than or equal, mutually exclusive with VERSION_GT 41 | # :type VERSION_GTE: string 42 | # :param VERSION_SELECTED_OUTPUT: name of variable to output selected version into, optional 43 | # :type VERSION_SELECTED_OUTPUT: string 44 | # 45 | # @public 46 | # 47 | macro(osrf_testing_tools_cpp_require_googletest) 48 | # Make sure this was only called once. 49 | if(OSRF_TESTING_TOOLS_CPP_REQUIRE_GOOGLETEST_VERSION_SETUP) 50 | set(error_msg "osrf_testing_tools_cpp_require_googletest():") 51 | set(error_msg "${error_msg} googletest already setup for version") 52 | set(error_msg "${error_msg} '${OSRF_TESTING_TOOLS_CPP_REQUIRE_GOOGLETEST_VERSION_SETUP}'") 53 | message(FATAL_ERROR ${error_msg}) 54 | endif() 55 | 56 | # Check if any requested versions match constraints 57 | _osrf_testing_tools_cpp_require_googletest(__return_variable ${ARGN}) 58 | endmacro() 59 | 60 | function(_osrf_testing_tools_cpp_filter_versions 61 | valid_version_indexes_var_name 62 | version_list 63 | ) 64 | # Arguments are validated in the calling function, _osrf_testing_tools_cpp_require_googletest() 65 | cmake_parse_arguments(ARG 66 | "" 67 | "VERSION_EQ;VERSION_LT;VERSION_LTE;VERSION_GT;VERSION_GTE;VERSION_SELECTED_OUTPUT" 68 | "" 69 | ${ARGN}) 70 | 71 | set(valid_version_indexes) 72 | set(current_index 0) 73 | foreach(version IN LISTS ${version_list}) 74 | set(version_valid FALSE) 75 | if(ARG_VERSION_EQ) 76 | if(version VERSION_EQUAL ARG_VERSION_EQ) 77 | set(version_valid TRUE) 78 | endif() 79 | else() 80 | if(ARG_VERSION_LT) 81 | if(version VERSION_LESS ARG_VERSION_LT) 82 | set(version_valid TRUE) 83 | endif() 84 | endif() 85 | if(ARG_VERSION_LTE) 86 | if(version VERSION_LESS ARG_VERSION_LTE OR version EQUAL ARG_VERSION_LTE) 87 | set(version_valid TRUE) 88 | endif() 89 | endif() 90 | if(ARG_VERSION_GT) 91 | if(version VERSION_GREATER ARG_VERSION_GT) 92 | set(version_valid TRUE) 93 | endif() 94 | endif() 95 | if(ARG_VERSION_GTE) 96 | if(version VERSION_GREATER ARG_VERSION_GTE OR version EQUAL ARG_VERSION_GTE) 97 | set(version_valid TRUE) 98 | endif() 99 | endif() 100 | endif() 101 | if(version_valid) 102 | list(APPEND valid_version_indexes ${current_index}) 103 | endif() 104 | math(EXPR current_index "${current_index} + 1") 105 | endforeach() 106 | set(${valid_version_indexes_var_name} ${valid_version_indexes} PARENT_SCOPE) 107 | endfunction() 108 | 109 | function(_osrf_testing_tools_cpp_require_googletest return_variable) 110 | cmake_parse_arguments(ARG 111 | "" 112 | "VERSION_EQ;VERSION_LT;VERSION_LTE;VERSION_GT;VERSION_GTE;VERSION_SELECTED_OUTPUT;VENDOR_DIR" 113 | "" 114 | ${ARGN}) 115 | if(ARG_UNPARSED_ARGUMENTS) 116 | message(FATAL_ERROR 117 | "osrf_testing_tools_cpp_require_googletest(): unknown args: ${ARG_UNPARSED_ARGUMENTS}") 118 | endif() 119 | 120 | # Check for use of mutually exclusive options 121 | if(ARG_VERSION_EQ AND (ARG_VERSION_LT OR ARG_VERSION_LTE OR ARG_VERSION_GT OR ARG_VERSION_GTE)) 122 | message(FATAL_ERROR 123 | "osrf_testing_tools_cpp_require_googletest(): VERSION_EQ is a mutually exclusive option") 124 | endif() 125 | if(ARG_VERSION_GT AND ARG_VERSION_GTE) 126 | message(FATAL_ERROR 127 | "osrf_testing_tools_cpp_require_googletest(): VERSION_GT and VERSION_GTE used together") 128 | endif() 129 | if(ARG_VERSION_LT AND ARG_VERSION_LTE) 130 | message(FATAL_ERROR 131 | "osrf_testing_tools_cpp_require_googletest(): VERSION_LT and VERSION_LTE used together") 132 | endif() 133 | 134 | osrf_testing_tools_cpp_get_googletest_versions(versions locations md5s) 135 | 136 | # First generate a list of versions which fit the constraints. 137 | _osrf_testing_tools_cpp_filter_versions(valid_version_indexes versions ${ARGN}) 138 | list(LENGTH valid_version_indexes valid_version_indexes_length) 139 | if(valid_version_indexes_length EQUAL 0) 140 | message(FATAL_ERROR 141 | "No valid googletest version found in provided versions: ${versions}") 142 | endif() 143 | # Use the newest version available, of the valid versions. 144 | set(valid_versions) 145 | set(newest_valid_version_index 0) 146 | list(GET versions 0 newest_valid_version) 147 | foreach(current_valid_version_index IN LISTS valid_version_indexes) 148 | list(GET versions ${current_valid_version_index} current_valid_version) 149 | list(APPEND valid_versions ${current_valid_version}) 150 | if(current_valid_version VERSION_GREATER newest_valid_version) 151 | set(newest_valid_version_index ${current_valid_version_index}) 152 | set(newest_valid_version ${current_valid_version}) 153 | endif() 154 | endforeach() 155 | message(STATUS 156 | "googletest version '${newest_valid_version}' selected, of versions: '${valid_versions}'") 157 | 158 | if(ARG_VENDOR_DIR) 159 | set(VENDOR_DIR ${ARG_VENDOR_DIR}) 160 | else() 161 | if(NOT DEFINED osrf_testing_tools_cpp_DIR) 162 | message(FATAL_ERROR 163 | "Cannot locate the googletest vendor directory because osrf_testing_tools_cpp " 164 | "was not found and the VENDOR_DIR argument was not used.") 165 | endif() 166 | set(VENDOR_DIR "${osrf_testing_tools_cpp_DIR}/../../../share/osrf_testing_tools_cpp/vendor") 167 | endif() 168 | 169 | list(GET locations ${newest_valid_version_index} newest_valid_location) 170 | set(newest_valid_location "${VENDOR_DIR}/${newest_valid_location}") 171 | message(STATUS "building googletest from '${newest_valid_location}'...") 172 | 173 | list(GET md5s ${newest_valid_version_index} md5) 174 | 175 | set(add_external_project_file 176 | "${VENDOR_DIR}/google/googletest/googletest-external-project-add.cmake.in") 177 | 178 | osrf_testing_tools_cpp_extract_and_build_googletest( 179 | ${newest_valid_location} ${newest_valid_version} ${md5} ${add_external_project_file} 180 | ) 181 | set(OSRF_TESTING_TOOLS_CPP_REQUIRE_GOOGLETEST_VERSION_SETUP ${newest_valid_version}) 182 | endfunction() 183 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/demangle.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__DEMANGLE_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__DEMANGLE_HPP_ 17 | 18 | #ifndef _WIN32 19 | // Includes for abi::__cxa_demangle. 20 | #include 21 | #include 22 | #include 23 | #endif 24 | #include 25 | #include 26 | 27 | namespace osrf_testing_tools_cpp 28 | { 29 | 30 | /// Return the demangled version of the given type string, or the original string if unable. 31 | std::string 32 | demangle_str(const std::string & mangled_typeid_name) 33 | { 34 | #if !defined(_WIN32) 35 | int status = 0; 36 | std::unique_ptr res { 37 | abi::__cxa_demangle(mangled_typeid_name.c_str(), NULL, NULL, &status), 38 | std::free 39 | }; 40 | 41 | return (status == 0) ? res.get() : mangled_typeid_name; 42 | #else 43 | return mangled_typeid_name; 44 | #endif 45 | } 46 | 47 | /// Return the demangle name of the instance of type T. 48 | template 49 | std::string 50 | demangle(const T & instance) 51 | { 52 | (void)instance; 53 | // Cannot do demangling if on Windows or if we want to avoid memory allocation. 54 | #if !defined(_WIN32) 55 | std::string mangled_typeid_name = typeid(T).name(); 56 | 57 | return demangle_str(mangled_typeid_name); 58 | #else 59 | return typeid(T).name(); 60 | #endif 61 | } 62 | 63 | } // namespace osrf_testing_tools_cpp 64 | 65 | #endif // OSRF_TESTING_TOOLS_CPP__DEMANGLE_HPP_ 66 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/macros.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MACROS_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MACROS_HPP_ 17 | 18 | #define OSRF_TESTING_TOOLS_CPP_STRING_JOIN(arg1, arg2) \ 19 | OSRF_TESTING_TOOLS_CPP_DO_STRING_JOIN(arg1, arg2) 20 | #define OSRF_TESTING_TOOLS_CPP_DO_STRING_JOIN(arg1, arg2) arg1 ## arg2 21 | 22 | #endif // OSRF_TESTING_TOOLS_CPP__MACROS_HPP_ 23 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/initialize.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__INITIALIZE_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__INITIALIZE_HPP_ 17 | 18 | #include "./visibility_control.hpp" 19 | 20 | namespace osrf_testing_tools_cpp 21 | { 22 | namespace memory_tools 23 | { 24 | 25 | /// Return true if initialized, otherwise false. 26 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 27 | bool 28 | initialized(); 29 | 30 | /// Install hooks into dynamic memory functions. 31 | /** 32 | * May do nothing on some platforms, as installing the hooks happens during 33 | * linking rather than at runtime. 34 | * If necessary, however, this function will replace the dynamic memory hooks. 35 | * 36 | * This function, and it's counterpart `uninitialize()`, are meant to 37 | * be called infrequently, if you want to disable the checked temporarily, use 38 | * thread-specific `enable_monitoring()`/`disable_monitoring()` functions or 39 | * the global functions 40 | * `enable_monitoring_in_all_threads()`/`disable_monitoring_in_all_threads()`. 41 | * 42 | * May throw an exception if unable to install memory allocation hooks. 43 | * On platforms where memory tools are not supported, nothing will happen. 44 | * 45 | * More may need to be done in order to have memory tools installed, like using 46 | * the `LD_PRELOAD` environment variable on Linux. 47 | * See other documentation for details. 48 | * 49 | * This function may allocate memory and then free it to test that the hooks 50 | * have been installed. 51 | * 52 | * \throws std::runtime_error if hooks cannot be installed. 53 | */ 54 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 55 | void 56 | initialize(); 57 | 58 | /// Disable, or uninstall if possible, hooks in the dynamic memory functions. 59 | /** 60 | * This function will attempt to remove the hooks in the dynamic memory 61 | * functions, but will return false if it cannot. 62 | * Even if the hooks cannot be uninstalled, calling this function will prevent 63 | * the hooks from being called. 64 | * Calling this function before `initialize()` does nothing, and 65 | * false will be returned. 66 | * 67 | * Also resets all state and clears all callbacks. 68 | * 69 | * \returns true if actually uninstalled or not installed yet, false otherwise. 70 | */ 71 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 72 | bool 73 | uninitialize(); 74 | 75 | } // namespace memory_tools 76 | } // namespace osrf_testing_tools_cpp 77 | 78 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__INITIALIZE_HPP_ 79 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__IS_WORKING_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__IS_WORKING_HPP_ 17 | 18 | #include 19 | #include 20 | 21 | #include "./visibility_control.hpp" 22 | 23 | namespace osrf_testing_tools_cpp 24 | { 25 | namespace memory_tools 26 | { 27 | 28 | /// Return true if memory tools is enabled, installed (LD_PRELOAD was done), and working. 29 | /** 30 | * This works by temporarily installing a on_malloc hook and then calling 31 | * malloc in a way that cannot be optimized out by the compiler. 32 | */ 33 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 34 | bool 35 | is_working(); 36 | 37 | /// Copy an input string into allocated memory, guaranteeing malloc is called. 38 | /** 39 | * Makes sure that the compiler doesn't optimize the malloc and free out. 40 | * The content of the input string doesn't matter, but should be non-empty. 41 | */ 42 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 43 | void 44 | guaranteed_malloc(const std::string & str); 45 | 46 | } // namespace memory_tools 47 | } // namespace osrf_testing_tools_cpp 48 | 49 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__IS_WORKING_HPP_ 50 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/memory_tools.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code to do replacing of malloc/free/etc... inspired by: 16 | // https://dxr.mozilla.org/mozilla-central/rev/ 17 | // cc9c6cd756cb744596ba039dcc5ad3065a7cc3ea/memory/build/replace_malloc.c 18 | 19 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MEMORY_TOOLS_HPP_ 20 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MEMORY_TOOLS_HPP_ 21 | 22 | #include "./initialize.hpp" 23 | #include "./is_working.hpp" 24 | #include "./memory_tools_service.hpp" 25 | #include "./monitoring.hpp" 26 | #include "./register_hooks.hpp" 27 | #include "./testing_helpers.hpp" 28 | #include "./visibility_control.hpp" 29 | 30 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MEMORY_TOOLS_HPP_ 31 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/memory_tools_service.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_HPP_ 17 | 18 | #include "./stack_trace.hpp" 19 | #include "./visibility_control.hpp" 20 | 21 | namespace osrf_testing_tools_cpp 22 | { 23 | namespace memory_tools 24 | { 25 | 26 | /// Forward declaration of private MemoryToolsService factory class. 27 | class MemoryToolsServiceFactory; 28 | 29 | class MemoryToolsServiceImpl; 30 | 31 | enum class MemoryFunctionType 32 | { 33 | Malloc, 34 | Realloc, 35 | Calloc, 36 | Free, 37 | }; 38 | 39 | /// Service injected in to user callbacks which allow them to control behavior. 40 | /** 41 | * This is a Service (in the terminology of the dependency injection pattern) 42 | * which is given to user callbacks which allows the user to control the 43 | * behavior of the memory tools test suite, like whether or not to log the 44 | * occurrence, print a backtrace, or make a gtest assert. 45 | * 46 | * Creation of the MemoryToolsService is prevented publicly, so to enforce the 47 | * functions are only called from within a memory tools callback. 48 | * Similarly, the instance given by the callback parameter is only valid until 49 | * the callback returns, therefore it should not be stored globally and called 50 | * later. 51 | * 52 | * The default behavior is that a single line message about the event is 53 | * printed to stderr and a gtest assertion fails if between the 54 | * `assert_no_*_{begin,end}()` function calls for a given memory operation. 55 | * However, you can avoid both behaviors by calling ignore(), or just avoid 56 | * the gtest failure by calling ignore_but_log(). 57 | * 58 | * You can have it include a backtrace to see where the memory-related call is 59 | * originating from by calling print_backtrace() before returning. 60 | * 61 | * The user's callback, if set, will occur before memory operations. 62 | * The gtest failure, if not ignored, will also occur before memory operations. 63 | * Any logging activity occurs after the memory operations. 64 | */ 65 | struct MemoryToolsService 66 | { 67 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 68 | virtual ~MemoryToolsService(); 69 | 70 | /// Return the memory function type. 71 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 72 | MemoryFunctionType 73 | get_memory_function_type() const; 74 | 75 | /// Return the memory function type as a string. 76 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 77 | const char * 78 | get_memory_function_type_str() const; 79 | 80 | /// If called last, no log message for the dynamic memory event will be logged. 81 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 82 | void 83 | ignore(); 84 | 85 | /// If called last, a log message for the dynamic memory event will be logged. 86 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 87 | void 88 | unignore(); 89 | 90 | /// Adds a backtrace to the log message. 91 | /** Repeated calls do nothing, and only prints if a log is also printed. */ 92 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 93 | void 94 | print_backtrace(); 95 | 96 | /// Returns a stack trace object for introspection. 97 | /** 98 | * Pointer should not be used after MemoryToolsService is out of scope. 99 | * Will return nullptr if a stack trace is not available, e.g. on Windows. 100 | */ 101 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 102 | StackTrace * 103 | get_stack_trace(); 104 | 105 | /// Return the address of the source memory function. 106 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 107 | const char * 108 | get_source_function_name() const; 109 | 110 | protected: 111 | explicit MemoryToolsService( 112 | MemoryFunctionType memory_function_type, 113 | const char * source_function_name); 114 | 115 | std::shared_ptr impl_; 116 | 117 | friend MemoryToolsServiceFactory; 118 | }; 119 | 120 | } // namespace memory_tools 121 | } // namespace osrf_testing_tools_cpp 122 | 123 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_HPP_ 124 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/monitoring.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MONITORING_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MONITORING_HPP_ 17 | 18 | #include "./visibility_control.hpp" 19 | 20 | namespace osrf_testing_tools_cpp 21 | { 22 | namespace memory_tools 23 | { 24 | 25 | /// Return true if the memory tools hooks are enabled. 26 | /** 27 | * Hooks will be enabled if either the thread-specific `enable()` or the 28 | * global `enable_in_all_threads()` have been called. 29 | * 30 | * The thread-specific `disable()` will disable hooks in that thread even if 31 | * `enable_in_all_threads()` has been called. 32 | * To disable hooks in a thread while still respecting 33 | * `enable_in_all_threads()`, use the `unset_thread_specific_enable()` 34 | * function. 35 | * 36 | * The thread-specific `enable()` will override the global 37 | * `disable_in_all_threads()`, even if `disable_in_all_threads()` was called 38 | * second. 39 | * 40 | * For granular control of hooks in threads, avoid `enable_in_all_threads()`. 41 | * 42 | * If `install()` has not been called, then this will return false. 43 | */ 44 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 45 | bool 46 | monitoring_enabled(); 47 | 48 | /// Enable memory tools hooks in dynamic memory functions, thread-specific. 49 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 50 | void 51 | enable_monitoring(); 52 | 53 | /// Disable memory tools hooks in dynamic memory functions, thread-specific. 54 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 55 | void 56 | disable_monitoring(); 57 | 58 | /// Disable hooks if not enabled globally, thread-specific and default state. 59 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 60 | void 61 | unset_thread_specific_monitoring_enable(); 62 | 63 | /// Enable memory tools hooks in dynamic memory functions, in all threads. 64 | /** \returns the previous state */ 65 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 66 | bool 67 | enable_monitoring_in_all_threads(); 68 | 69 | /// Disable memory tools hooks in dynamic memory functions, in all threads. 70 | /** \returns the previous state */ 71 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 72 | bool 73 | disable_monitoring_in_all_threads(); 74 | 75 | } // namespace memory_tools 76 | } // namespace osrf_testing_tools_cpp 77 | 78 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MONITORING_HPP_ 79 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/register_hooks.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__REGISTER_HOOKS_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__REGISTER_HOOKS_HPP_ 17 | 18 | #include 19 | #include 20 | 21 | #include "./memory_tools_service.hpp" 22 | #include "./visibility_control.hpp" 23 | 24 | namespace osrf_testing_tools_cpp 25 | { 26 | namespace memory_tools 27 | { 28 | 29 | /// Signature for callback on a call to a dynamic memory function. 30 | using MemoryToolsCallback = std::function; 31 | /// Simpler signature. 32 | using MemoryToolsSimpleCallback = std::function; 33 | 34 | using AnyMemoryToolsCallback = std::variant< 35 | MemoryToolsCallback, 36 | MemoryToolsSimpleCallback, 37 | std::nullptr_t>; 38 | 39 | /// Register a hook to be called on malloc(). 40 | /** 41 | * Some dynamic memory calls are expected (the implementation of memory tools), 42 | * so only "unexpected" calls to dynamic memory functions cause the hooks to 43 | * be called. 44 | * 45 | * Replaces any existing hook, pass nullptr to "unregister". 46 | * 47 | * \throws std::bad_alloc if allocating storage for the callback fails 48 | */ 49 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 50 | void 51 | on_malloc(AnyMemoryToolsCallback callback); 52 | 53 | /// Get the current on_malloc callback if set, otherwise null. 54 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 55 | AnyMemoryToolsCallback 56 | get_on_malloc(); 57 | 58 | /// Call the registered callback for malloc. 59 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 60 | void 61 | dispatch_malloc(MemoryToolsService & service); 62 | 63 | /// Register a hook to be called on realloc(). 64 | /** 65 | * Replaces any existing hook, pass nullptr to "unregister". 66 | * 67 | * \throws std::bad_alloc if allocating storage for the callback fails 68 | */ 69 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 70 | void 71 | on_realloc(AnyMemoryToolsCallback callback); 72 | 73 | /// Get the current on_realloc callback if set, otherwise null. 74 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 75 | AnyMemoryToolsCallback 76 | get_on_realloc(); 77 | 78 | /// Call the registered callback for realloc. 79 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 80 | void 81 | dispatch_realloc(MemoryToolsService & service); 82 | 83 | /// Register a hook to be called on calloc(). 84 | /** 85 | * Replaces any existing hook, pass nullptr to "unregister". 86 | * 87 | * \throws std::bad_alloc if allocating storage for the callback fails 88 | */ 89 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 90 | void 91 | on_calloc(AnyMemoryToolsCallback callback); 92 | 93 | /// Get the current on_calloc callback if set, otherwise null. 94 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 95 | AnyMemoryToolsCallback 96 | get_on_calloc(); 97 | 98 | /// Call the registered callback for calloc. 99 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 100 | void 101 | dispatch_calloc(MemoryToolsService & service); 102 | 103 | /// Register a hook to be called on free(). 104 | /** 105 | * Replaces any existing hook, pass nullptr to "unregister". 106 | * 107 | * \throws std::bad_alloc if allocating storage for the callback fails 108 | */ 109 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 110 | void 111 | on_free(AnyMemoryToolsCallback callback); 112 | 113 | /// Get the current on_free callback if set, otherwise null. 114 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 115 | AnyMemoryToolsCallback 116 | get_on_free(); 117 | 118 | /// Call the registered callback for free. 119 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 120 | void 121 | dispatch_free(MemoryToolsService & service); 122 | 123 | } // namespace memory_tools 124 | } // namespace osrf_testing_tools_cpp 125 | 126 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__REGISTER_HOOKS_HPP_ 127 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/stack_trace.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__STACK_TRACE_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__STACK_TRACE_HPP_ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "./visibility_control.hpp" 24 | 25 | namespace osrf_testing_tools_cpp 26 | { 27 | namespace memory_tools 28 | { 29 | 30 | struct SourceLocationImpl; 31 | 32 | struct SourceLocation 33 | { 34 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 35 | explicit SourceLocation(std::shared_ptr impl); 36 | 37 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 38 | virtual ~SourceLocation(); 39 | 40 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 41 | const std::string & 42 | function() const; 43 | 44 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 45 | const std::string & 46 | filename() const; 47 | 48 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 49 | size_t 50 | line() const; 51 | 52 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 53 | size_t 54 | column() const; 55 | 56 | private: 57 | std::shared_ptr impl_; 58 | }; 59 | 60 | struct TraceImpl; 61 | 62 | struct Trace 63 | { 64 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 65 | explicit Trace(std::unique_ptr impl); 66 | 67 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 68 | explicit Trace(const Trace & other); 69 | 70 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 71 | virtual ~Trace(); 72 | 73 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 74 | void * 75 | address() const; 76 | 77 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 78 | size_t 79 | index_in_stack() const; 80 | 81 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 82 | const std::string & 83 | object_filename() const; 84 | 85 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 86 | const std::string & 87 | object_function() const; 88 | 89 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 90 | const SourceLocation & 91 | source_location() const; 92 | 93 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 94 | const std::vector & 95 | inlined_source_locations() const; 96 | 97 | private: 98 | std::unique_ptr impl_; 99 | }; 100 | 101 | struct StackTraceImpl; 102 | 103 | /// Return true if the given regex is found to match the object_filename of any trace. 104 | template 105 | bool 106 | matches_any_object_filename_of_traces( 107 | const std::basic_regex & regex, 108 | const std::vector & traces) 109 | { 110 | for (const auto & trace : traces) { 111 | if (std::regex_search(trace.object_filename(), regex)) { 112 | return true; 113 | } 114 | } 115 | return false; 116 | } 117 | 118 | /// Return true if the given regex is found to match the object_function of any trace. 119 | template 120 | bool 121 | matches_any_object_function_of_traces( 122 | const std::basic_regex & regex, 123 | const std::vector & traces) 124 | { 125 | for (const auto & trace : traces) { 126 | if (std::regex_search(trace.object_function(), regex)) { 127 | return true; 128 | } 129 | } 130 | return false; 131 | } 132 | 133 | struct StackTrace 134 | { 135 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 136 | explicit StackTrace(std::unique_ptr impl); 137 | 138 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 139 | virtual ~StackTrace(); 140 | 141 | /// Return the thread id of the thread from which the call stack originates. 142 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 143 | std::thread::id 144 | thread_id() const; 145 | 146 | /// Return a list of traces in the call stack. 147 | /** Limited to a max call stack depth of 256 */ 148 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 149 | const std::vector & 150 | get_traces() const; 151 | 152 | /// Return a list of traces which end with the last call to the function name given. 153 | /** 154 | * This can be used, in combination with the name of the replacement memory 155 | * function, to avoid a lot of boilerplate calls in the stack that are part 156 | * of memory tools itself. 157 | * 158 | * An empty vector returned indicates the function name was not found in the 159 | * callstack. 160 | */ 161 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 162 | std::vector 163 | get_traces_from_function_name(const char * function_name) const; 164 | 165 | /// Return true if the given regex is found to match the object_filename of any trace. 166 | template 167 | bool 168 | matches_any_object_filename(const std::basic_regex & regex) const 169 | { 170 | return matches_any_object_filename_of_traces(regex, this->get_traces()); 171 | } 172 | 173 | /// Return true if the given regex is found to match the object_function of any trace. 174 | template 175 | bool 176 | matches_any_object_function(const std::basic_regex & regex) const 177 | { 178 | return matches_any_object_function_of_traces(regex, this->get_traces()); 179 | } 180 | 181 | private: 182 | std::unique_ptr impl_; 183 | }; 184 | 185 | } // namespace memory_tools 186 | } // namespace osrf_testing_tools_cpp 187 | 188 | #endif // OSRF_TESTING_TOOLS_CPP__STACK_TRACE_HPP_ 189 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/testing_helpers.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__TESTING_HELPERS_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__TESTING_HELPERS_HPP_ 17 | 18 | #include "./register_hooks.hpp" 19 | #include "./visibility_control.hpp" 20 | 21 | namespace osrf_testing_tools_cpp 22 | { 23 | namespace memory_tools 24 | { 25 | 26 | /// Register callback to be called when malloc is unexpected. 27 | /** 28 | * Uses and is overridden by on_malloc(). 29 | * 30 | * \sa expect_no_malloc_begin() 31 | * \sa expect_no_malloc_end() 32 | */ 33 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 34 | void 35 | on_unexpected_malloc(AnyMemoryToolsCallback callback); 36 | 37 | /// Call corresponding callback if the given statements call malloc. 38 | #define EXPECT_NO_MALLOC(statements) \ 39 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_begin(); \ 40 | statements; \ 41 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_end() 42 | 43 | /// Return true if malloc is expected. 44 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 45 | bool 46 | malloc_expected(); 47 | 48 | /// Toggle calling of callback on from within malloc. 49 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 50 | void 51 | expect_no_malloc_begin(); 52 | 53 | /// Toggle calling of callback off from within malloc. 54 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 55 | void 56 | expect_no_malloc_end(); 57 | 58 | /// Register callback to be called when realloc is unexpected. 59 | /** 60 | * Uses and is overridden by on_realloc(). 61 | * 62 | * \sa expect_no_realloc_begin() 63 | * \sa expect_no_realloc_end() 64 | */ 65 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 66 | void 67 | on_unexpected_realloc(AnyMemoryToolsCallback callback); 68 | 69 | /// Call corresponding callback if the given statements call realloc. 70 | #define EXPECT_NO_REALLOC(statements) \ 71 | osrf_testing_tools_cpp::memory_tools::expect_no_realloc_begin(); \ 72 | statements; \ 73 | osrf_testing_tools_cpp::memory_tools::expect_no_realloc_end() 74 | 75 | /// Return true if realloc is expected. 76 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 77 | bool 78 | realloc_expected(); 79 | 80 | /// Toggle calling of callback on from within realloc. 81 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 82 | void 83 | expect_no_realloc_begin(); 84 | 85 | /// Toggle calling of callback off from within realloc. 86 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 87 | void 88 | expect_no_realloc_end(); 89 | 90 | /// Register callback to be called when calloc is unexpected. 91 | /** 92 | * Uses and is overridden by on_calloc(). 93 | * 94 | * \sa expect_no_calloc_begin() 95 | * \sa expect_no_calloc_end() 96 | */ 97 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 98 | void 99 | on_unexpected_calloc(AnyMemoryToolsCallback callback); 100 | 101 | /// Call corresponding callback if the given statements call calloc. 102 | #define EXPECT_NO_CALLOC(statements) \ 103 | osrf_testing_tools_cpp::memory_tools::expect_no_calloc_begin(); \ 104 | statements; \ 105 | osrf_testing_tools_cpp::memory_tools::expect_no_calloc_end() 106 | 107 | /// Return true if calloc is expected. 108 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 109 | bool 110 | calloc_expected(); 111 | 112 | /// Toggle calling of callback on from within calloc. 113 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 114 | void 115 | expect_no_calloc_begin(); 116 | 117 | /// Toggle calling of callback off from within calloc. 118 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 119 | void 120 | expect_no_calloc_end(); 121 | 122 | /// Register callback to be called when free is unexpected. 123 | /** 124 | * Uses and is overridden by on_free(). 125 | * 126 | * \sa expect_no_free_begin() 127 | * \sa expect_no_free_end() 128 | */ 129 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 130 | void 131 | on_unexpected_free(AnyMemoryToolsCallback callback); 132 | 133 | /// Call corresponding callback if the given statements call free. 134 | #define EXPECT_NO_FREE(statements) \ 135 | osrf_testing_tools_cpp::memory_tools::expect_no_free_begin(); \ 136 | statements; \ 137 | osrf_testing_tools_cpp::memory_tools::expect_no_free_end() 138 | 139 | /// Return true if free is expected. 140 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 141 | bool 142 | free_expected(); 143 | 144 | /// Toggle calling of callback on from within free. 145 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 146 | void 147 | expect_no_free_begin(); 148 | 149 | /// Toggle calling of callback off from within free. 150 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 151 | void 152 | expect_no_free_end(); 153 | 154 | /// Start checking for unexpected memory operations. 155 | #define EXPECT_NO_MEMORY_OPERATIONS_BEGIN() \ 156 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_begin(); \ 157 | osrf_testing_tools_cpp::memory_tools::expect_no_realloc_begin(); \ 158 | osrf_testing_tools_cpp::memory_tools::expect_no_calloc_begin(); \ 159 | osrf_testing_tools_cpp::memory_tools::expect_no_free_begin() 160 | 161 | /// Stop checking for unexpected memory operations. 162 | #define EXPECT_NO_MEMORY_OPERATIONS_END() \ 163 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_end(); \ 164 | osrf_testing_tools_cpp::memory_tools::expect_no_realloc_end(); \ 165 | osrf_testing_tools_cpp::memory_tools::expect_no_calloc_end(); \ 166 | osrf_testing_tools_cpp::memory_tools::expect_no_free_end() 167 | 168 | /// Call corresponding callback assert on any memory operation. 169 | #define EXPECT_NO_MEMORY_OPERATIONS(statements) \ 170 | EXPECT_NO_MEMORY_OPERATIONS_BEGIN(); \ 171 | statements; \ 172 | EXPECT_NO_MEMORY_OPERATIONS_END() 173 | 174 | } // namespace memory_tools 175 | } // namespace osrf_testing_tools_cpp 176 | 177 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__TESTING_HELPERS_HPP_ 178 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/verbosity.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__VERBOSITY_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__VERBOSITY_HPP_ 17 | 18 | #include "./visibility_control.hpp" 19 | 20 | namespace osrf_testing_tools_cpp 21 | { 22 | namespace memory_tools 23 | { 24 | 25 | enum class VerbosityLevel { 26 | quiet, 27 | debug, 28 | trace, 29 | }; 30 | 31 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 32 | VerbosityLevel 33 | get_verbosity_level(); 34 | 35 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 36 | VerbosityLevel 37 | set_verbosity_level(VerbosityLevel verbosity_level); 38 | 39 | } // namespace memory_tools 40 | } // namespace osrf_testing_tools_cpp 41 | 42 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__VERBOSITY_HPP_ 43 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/visibility_control.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__VISIBILITY_CONTROL_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__VISIBILITY_CONTROL_HPP_ 17 | 18 | // This logic was borrowed (then namespaced) from the examples on the gcc wiki: 19 | // https://gcc.gnu.org/wiki/Visibility 20 | 21 | #if defined _WIN32 || defined __CYGWIN__ 22 | #ifdef __GNUC__ 23 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_EXPORT __attribute__ ((dllexport)) 24 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_IMPORT __attribute__ ((dllimport)) 25 | #else 26 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_EXPORT __declspec(dllexport) 27 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_IMPORT __declspec(dllimport) 28 | #endif 29 | #ifdef OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_BUILDING_DLL 30 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_EXPORT 31 | #else 32 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_IMPORT 33 | #endif 34 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC_TYPE OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 35 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_LOCAL 36 | #else 37 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_EXPORT __attribute__ ((visibility("default"))) 38 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_IMPORT 39 | #if __GNUC__ >= 4 40 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC __attribute__ ((visibility("default"))) 41 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_LOCAL __attribute__ ((visibility("hidden"))) 42 | #else 43 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC 44 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_LOCAL 45 | #endif 46 | #define OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC_TYPE 47 | #endif 48 | 49 | #endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__VISIBILITY_CONTROL_HPP_ 50 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/scope_exit.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__SCOPE_EXIT_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__SCOPE_EXIT_HPP_ 17 | 18 | #include 19 | 20 | #include "./macros.hpp" 21 | 22 | namespace osrf_testing_tools_cpp 23 | { 24 | 25 | template 26 | struct ScopeExit 27 | { 28 | explicit ScopeExit(Callable callable) 29 | : callable_(callable) {} 30 | ~ScopeExit() {callable_();} 31 | 32 | private: 33 | Callable callable_; 34 | }; 35 | 36 | template 37 | ScopeExit 38 | make_scope_exit(Callable callable) 39 | { 40 | return ScopeExit(callable); 41 | } 42 | 43 | } // namespace osrf_testing_tools_cpp 44 | 45 | #define OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(code) \ 46 | auto OSRF_TESTING_TOOLS_CPP_STRING_JOIN(scope_exit_, __LINE__) = \ 47 | osrf_testing_tools_cpp::make_scope_exit([&]() {code;}) 48 | 49 | #endif // OSRF_TESTING_TOOLS_CPP__SCOPE_EXIT_HPP_ 50 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/osrf_testing_tools_cppConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set(__prefix_dir "${osrf_testing_tools_cpp_DIR}/../../..") 16 | set(__share_dir "${__prefix_dir}/share/osrf_testing_tools_cpp") 17 | 18 | include("${__share_dir}/cmake/memory_toolsExport.cmake") 19 | include("${__share_dir}/cmake/memory_tools_interposeExport.cmake") 20 | include("${__share_dir}/cmake/test_runnerExport.cmake") 21 | 22 | include("${__share_dir}/cmake/osrf_testing_tools_cpp_add_test.cmake") 23 | include("${__share_dir}/cmake/osrf_testing_tools_cpp_extract_and_build_googletest.cmake") 24 | include("${__share_dir}/cmake/osrf_testing_tools_cpp_get_googletest_versions.cmake") 25 | include("${__share_dir}/cmake/osrf_testing_tools_cpp_require_googletest.cmake") 26 | 27 | # setup target property for memory_tool's library preload env var 28 | define_property(TARGET 29 | PROPERTY LIBRARY_PRELOAD_ENVIRONMENT_VARIABLE 30 | BRIEF_DOCS "Environment variable needed to preload the associated library." 31 | FULL_DOCS "Environment variable needed to preload the associated library." 32 | ) 33 | define_property(TARGET 34 | PROPERTY LIBRARY_PRELOAD_ENVIRONMENT_IS_AVAILABLE 35 | BRIEF_DOCS "Indicator of whether memory_tools is available in the current build configuration." 36 | FULL_DOCS "Indicator of whether memory_tools is available in the current build configuration." 37 | ) 38 | string(REPLACE 39 | "memory_tools" "osrf_testing_tools_cpp::memory_tools" 40 | memory_tools_extra_test_env "@memory_tools_extra_test_env@") 41 | if(NOT memory_tools_extra_test_env) 42 | # On Windows, for example, this might be empty. 43 | set(memory_tools_extra_test_env "NO_LIBRARY_PRELOAD=1") 44 | endif() 45 | set_target_properties(osrf_testing_tools_cpp::memory_tools PROPERTIES 46 | LIBRARY_PRELOAD_ENVIRONMENT_VARIABLE ${memory_tools_extra_test_env}) 47 | set_target_properties(osrf_testing_tools_cpp::memory_tools PROPERTIES 48 | LIBRARY_PRELOAD_ENVIRONMENT_IS_AVAILABLE "@memory_tools_is_available@") 49 | 50 | # setup osrf_testing_tools_cpp_INCLUDE_DIRS so that header only things can be used without linking 51 | set(osrf_testing_tools_cpp_INCLUDE_DIRS "${__prefix_dir}/include") 52 | 53 | set(osrf_testing_tools_cpp_TARGETS 54 | osrf_testing_tools_cpp::memory_tools 55 | osrf_testing_tools_cpp::memory_tools_interpose) 56 | 57 | unset(__share_dir) 58 | unset(__prefix_dir) 59 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/osrf_testing_tools_cppConfigVersion.cmake.in: -------------------------------------------------------------------------------- 1 | set(PACKAGE_VERSION "@osrf_testing_tools_cpp_VERSION@") 2 | 3 | # Check whether the requested PACKAGE_FIND_VERSION is compatible 4 | if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") 5 | set(PACKAGE_VERSION_COMPATIBLE FALSE) 6 | else() 7 | set(PACKAGE_VERSION_COMPATIBLE TRUE) 8 | if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") 9 | set(PACKAGE_VERSION_EXACT TRUE) 10 | endif() 11 | endif() 12 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | osrf_testing_tools_cpp 7 | 2.3.0 8 | Testing tools for C++, and is used in various OSRF projects. 9 | 10 | Geoffrey Biggs 11 | 12 | Apache License 2.0 13 | 14 | William Woodall 15 | 16 | cmake 17 | 18 | 19 | cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(memory_tools) 2 | add_subdirectory(test_runner) 3 | 4 | set(memory_tools_extra_test_env "${memory_tools_extra_test_env}" PARENT_SCOPE) 5 | set(memory_tools_is_available "${memory_tools_is_available}" PARENT_SCOPE) 6 | set(memory_tools_src_dir_internal_testing_only 7 | "${memory_tools_src_dir_internal_testing_only}" PARENT_SCOPE) 8 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Integrate backward-cpp according to: 2 | # https://github.com/bombela/backward-cpp/tree/v1.5#modifying-cmake_module_path 3 | 4 | # Note, I had to use Backward_DIR since they provide a config file rather than a module... 5 | # list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/vendor/bombela/backward-cpp") 6 | set(Backward_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/bombela/backward-cpp") 7 | set(FPHSA_NAME_MISMATCHED TRUE) 8 | find_package(Backward REQUIRED) 9 | unset(FPHSA_NAME_MISMATCHED) 10 | 11 | add_library(memory_tools SHARED 12 | custom_memory_functions.cpp 13 | implementation_monitoring_override.cpp 14 | initialize.cpp 15 | is_working.cpp 16 | memory_tools_service.cpp 17 | monitoring.cpp 18 | register_hooks.cpp 19 | stack_trace.cpp 20 | testing_helpers.cpp 21 | verbosity.cpp 22 | ) 23 | 24 | target_include_directories(memory_tools 25 | PUBLIC 26 | $ 27 | $ 28 | ) 29 | target_link_libraries(memory_tools PRIVATE Backward::Backward) 30 | 31 | if(CMAKE_DL_LIBS) 32 | target_link_libraries(memory_tools PUBLIC ${CMAKE_DL_LIBS}) 33 | endif() 34 | 35 | target_compile_definitions(memory_tools 36 | PRIVATE "OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_BUILDING_DLL") 37 | 38 | add_library(memory_tools_interpose SHARED 39 | memory_tools.cpp 40 | ) 41 | target_link_libraries(memory_tools_interpose memory_tools) 42 | 43 | option(OSRF_TESTING_TOOLS_CPP_DISABLE_MEMORY_TOOLS 44 | "Disable environment configuration for memory tools" 45 | OFF) 46 | 47 | # Memory tools doesn't work on Windows right now. 48 | # TODO(wjwwood): If on aarch64, so not set the preload environment variables, until fixed. 49 | # see: https://github.com/osrf/osrf_testing_tools_cpp/issues/3 50 | if(WIN32 OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") 51 | set(OSRF_TESTING_TOOLS_CPP_DISABLE_MEMORY_TOOLS ON) 52 | endif() 53 | 54 | if (NOT OSRF_TESTING_TOOLS_CPP_DISABLE_MEMORY_TOOLS) 55 | set(memory_tools_is_available TRUE) 56 | if(APPLE) 57 | list(APPEND memory_tools_extra_test_env 58 | DYLD_INSERT_LIBRARIES=$) 59 | elseif(UNIX) 60 | list(APPEND memory_tools_extra_test_env 61 | LD_PRELOAD=$) 62 | endif() 63 | endif() 64 | 65 | install(TARGETS memory_tools 66 | EXPORT memory_tools 67 | ARCHIVE DESTINATION lib 68 | LIBRARY DESTINATION lib 69 | RUNTIME DESTINATION bin) 70 | 71 | install(EXPORT memory_tools 72 | DESTINATION share/${PROJECT_NAME}/cmake 73 | NAMESPACE "${PROJECT_NAME}::" 74 | FILE "memory_toolsExport.cmake" 75 | ) 76 | 77 | install(TARGETS memory_tools_interpose 78 | EXPORT memory_tools_interpose 79 | ARCHIVE DESTINATION lib 80 | LIBRARY DESTINATION lib 81 | RUNTIME DESTINATION bin) 82 | 83 | install(EXPORT memory_tools_interpose 84 | DESTINATION share/${PROJECT_NAME}/cmake 85 | NAMESPACE "${PROJECT_NAME}::" 86 | FILE "memory_tools_interposeExport.cmake" 87 | ) 88 | 89 | set(memory_tools_extra_test_env "${memory_tools_extra_test_env}" PARENT_SCOPE) 90 | set(memory_tools_is_available "${memory_tools_is_available}" PARENT_SCOPE) 91 | set(memory_tools_src_dir_internal_testing_only 92 | "$" PARENT_SCOPE) 93 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/count_function_occurrences_in_backtrace.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__COUNT_FUNCTION_OCCURRENCES_IN_BACKTRACE_HPP_ 16 | #define MEMORY_TOOLS__COUNT_FUNCTION_OCCURRENCES_IN_BACKTRACE_HPP_ 17 | 18 | #include "./safe_fwrite.hpp" 19 | 20 | #if defined(_WIN32) || defined(__QNXNTO__) || defined(__ANDROID__) 21 | 22 | // Include nothing for now. 23 | 24 | #else // defined(_WIN32) || defined(__ANDROID__) 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #endif // defined(_WIN32) || defined(__ANDROID__) 34 | 35 | namespace osrf_testing_tools_cpp 36 | { 37 | namespace memory_tools 38 | { 39 | 40 | class not_implemented : public std::logic_error 41 | { 42 | public: 43 | not_implemented() : std::logic_error("This function is not implemented.") {} 44 | }; 45 | 46 | template 47 | struct is_function_pointer 48 | : std::integral_constant::value && std::is_function::type>::value 50 | > 51 | {}; 52 | 53 | #if defined(_WIN32) || defined(__QNXNTO__) || defined(__ANDROID__) 54 | 55 | struct count_function_occurrences_in_backtrace_is_implemented : std::false_type {}; 56 | 57 | template 58 | size_t 59 | impl_count_function_occurrences_in_backtrace(void * function_address) 60 | { 61 | (void) function_address; 62 | throw not_implemented(); 63 | } 64 | 65 | #else // defined(_WIN32) || defined(__ANDROID__) 66 | 67 | struct count_function_occurrences_in_backtrace_is_implemented : std::true_type {}; 68 | 69 | template 70 | size_t 71 | impl_count_function_occurrences_in_backtrace(void * function_address) 72 | { 73 | // TODO(wjwwood): consider using backward-cpp's Stacktrace objects to implement this. 74 | void * address_list[MaxBacktraceSize]; 75 | int address_length = backtrace(address_list, sizeof(address_list) / sizeof(void *)); 76 | 77 | if (0 == address_length) { 78 | SAFE_FWRITE(stderr, "backtrace() failed\n"); 79 | exit(1); 80 | } 81 | 82 | size_t number_of_occurences = 0; 83 | int number_of_failed_dladdr = 0; 84 | for (int i = 0; i < address_length; ++i) { 85 | Dl_info info; 86 | if (!dladdr(address_list[i], &info)) { 87 | // do nothing, sometimes this fails on syscalls 88 | number_of_failed_dladdr++; 89 | continue; 90 | } 91 | if (function_address == info.dli_saddr) { 92 | number_of_occurences++; 93 | } 94 | } 95 | if (number_of_failed_dladdr == address_length) { 96 | SAFE_FWRITE(stderr, "all calls to dladdr failed, probably something wrong\n"); 97 | exit(1); 98 | } 99 | 100 | return number_of_occurences; 101 | } 102 | 103 | #endif // defined(_WIN32) 104 | 105 | /// Return the number of times a given function pointer occurs the backtrace. 106 | /** 107 | * This function will only look back into the backtrace as far as 108 | * `MaxBacktraceSize` allows. 109 | * 110 | * \return number of times a function appears in the backtrace 111 | * \throws osrf_testing_tools_cpp::memory_tools::not_implemented if not implemented 112 | */ 113 | template< 114 | int MaxBacktraceSize = 64, 115 | typename FunctionPointerT, 116 | typename = typename std::enable_if::value>::type> 117 | size_t 118 | count_function_occurrences_in_backtrace(FunctionPointerT function_address) 119 | { 120 | return impl_count_function_occurrences_in_backtrace( 121 | reinterpret_cast(function_address)); 122 | } 123 | 124 | } // namespace memory_tools 125 | } // namespace osrf_testing_tools_cpp 126 | 127 | #endif // MEMORY_TOOLS__COUNT_FUNCTION_OCCURRENCES_IN_BACKTRACE_HPP_ 128 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/custom_memory_functions.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__CUSTOM_MEMORY_FUNCTIONS_HPP_ 16 | #define MEMORY_TOOLS__CUSTOM_MEMORY_FUNCTIONS_HPP_ 17 | 18 | #include 19 | #include 20 | 21 | #include "./safe_fwrite.hpp" 22 | 23 | #if defined(__APPLE__) 24 | #include 25 | #define MALLOC_PRINTF malloc_printf 26 | #else // defined(__APPLE__) 27 | #define MALLOC_PRINTF printf 28 | #endif // defined(__APPLE__) 29 | 30 | namespace osrf_testing_tools_cpp 31 | { 32 | namespace memory_tools 33 | { 34 | 35 | void * 36 | custom_malloc(size_t size) noexcept; 37 | 38 | void * 39 | custom_malloc_with_original( 40 | size_t size, 41 | void * (*original_malloc)(size_t), 42 | const char * replacement_malloc_function_name, 43 | bool check_recursion) noexcept; 44 | 45 | void * 46 | custom_realloc(void * memory_in, size_t size) noexcept; 47 | 48 | void * 49 | custom_realloc_with_original( 50 | void * memory_in, 51 | size_t size, 52 | void * (*original_realloc)(void *, size_t), 53 | const char * replacement_realloc_function_name, 54 | bool check_recursion) noexcept; 55 | 56 | void * 57 | custom_calloc(size_t count, size_t size) noexcept; 58 | 59 | void * 60 | custom_calloc_with_original( 61 | size_t count, 62 | size_t size, 63 | void * (*original_calloc)(size_t, size_t), 64 | const char * replacement_calloc_function_name, 65 | bool check_recursion) noexcept; 66 | 67 | void 68 | custom_free(void * memory) noexcept; 69 | 70 | void 71 | custom_free_with_original( 72 | void * memory, 73 | void (*original_free)(void *), 74 | const char * replacement_free_function_name, 75 | bool check_recursion) noexcept; 76 | 77 | } // namespace memory_tools 78 | } // namespace osrf_testing_tools_cpp 79 | 80 | #endif // MEMORY_TOOLS__CUSTOM_MEMORY_FUNCTIONS_HPP_ 81 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/dispatch_callback.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__DISPATCH_CALLBACK_HPP_ 16 | #define MEMORY_TOOLS__DISPATCH_CALLBACK_HPP_ 17 | 18 | #include 19 | 20 | #include "osrf_testing_tools_cpp/memory_tools/register_hooks.hpp" 21 | 22 | namespace osrf_testing_tools_cpp 23 | { 24 | namespace memory_tools 25 | { 26 | 27 | inline 28 | void 29 | dispatch_callback( 30 | const AnyMemoryToolsCallback * user_callback, 31 | MemoryToolsService & service) 32 | { 33 | if (nullptr == user_callback) { 34 | return; 35 | } 36 | auto callback = user_callback; 37 | if (std::holds_alternative(*callback)) { 38 | return; 39 | } 40 | auto callback_ptr = std::get_if(callback); 41 | if (callback_ptr) { 42 | (*callback_ptr)(service); 43 | } 44 | auto simple_callback_ptr = std::get_if(callback); 45 | if (simple_callback_ptr) { 46 | (*simple_callback_ptr)(); 47 | } 48 | } 49 | 50 | } // namespace memory_tools 51 | } // namespace osrf_testing_tools_cpp 52 | 53 | #endif // MEMORY_TOOLS__DISPATCH_CALLBACK_HPP_ 54 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/impl/apple.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #if defined(__APPLE__) 16 | 17 | #include 18 | 19 | #include "./unix_common.hpp" 20 | 21 | // Pulled from: 22 | // https://github.com/emeryberger/Heap-Layers/blob/ 23 | // 076e9e7ef53b66380b159e40473b930f25cc353b/wrappers/macinterpose.h 24 | 25 | // The interposition data structure (just pairs of function pointers), 26 | // used an interposition table like the following: 27 | // 28 | 29 | typedef struct interpose_s 30 | { 31 | void * new_func; 32 | void * orig_func; 33 | } interpose_t; 34 | 35 | #define OSX_INTERPOSE(newf, oldf) \ 36 | __attribute__((used)) static const interpose_t \ 37 | macinterpose__ ## newf ## __ ## oldf __attribute__ ((section("__DATA, __interpose"))) = { \ 38 | reinterpret_cast(newf), \ 39 | reinterpret_cast(oldf), \ 40 | } 41 | 42 | extern "C" 43 | { 44 | 45 | void * 46 | apple_replacement_malloc(size_t size) 47 | { 48 | return unix_replacement_malloc(size, malloc); 49 | } 50 | 51 | void * 52 | apple_replacement_realloc(void * memory_in, size_t size) 53 | { 54 | return unix_replacement_realloc(memory_in, size, realloc); 55 | } 56 | 57 | void * 58 | apple_replacement_calloc(size_t count, size_t size) 59 | { 60 | return unix_replacement_calloc(count, size, calloc); 61 | } 62 | 63 | void 64 | apple_replacement_free(void * memory) 65 | { 66 | return unix_replacement_free(memory, free); 67 | } 68 | 69 | OSX_INTERPOSE(apple_replacement_malloc, malloc); 70 | OSX_INTERPOSE(apple_replacement_realloc, realloc); 71 | OSX_INTERPOSE(apple_replacement_calloc, calloc); 72 | OSX_INTERPOSE(apple_replacement_free, free); 73 | 74 | } // extern "C" 75 | 76 | // End Interpose. 77 | 78 | // on shared library load, find and store the original memory function locations 79 | static __attribute__((constructor,used)) void __apple_memory_tools_init(void) 80 | { 81 | complete_static_initialization(); 82 | } 83 | 84 | #endif // defined(__APPLE__) 85 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/impl/linux.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #if defined(__linux__) 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "./static_allocator.hpp" 22 | #include "./unix_common.hpp" 23 | 24 | template 25 | FunctionPointerT 26 | find_original_function(const char * name) 27 | { 28 | FunctionPointerT original_function = reinterpret_cast(dlsym(RTLD_NEXT, name)); 29 | if (!original_function) { 30 | fprintf(stderr, "failed to get original function '%s' with dlsym() and RTLD_NEXT\n", name); 31 | exit(1); // cannot throw, next best thing 32 | } 33 | // check to make sure we got one we want, see: 34 | // http://optumsoft.com/dangers-of-using-dlsym-with-rtld_next/ 35 | Dl_info dl_info; 36 | if (!dladdr(reinterpret_cast(original_function), &dl_info)) { 37 | fprintf(stderr, 38 | "failed to get information about function '%p' with dladdr()\n", 39 | reinterpret_cast(original_function)); 40 | exit(1); // cannot throw, next best thing 41 | } 42 | return original_function; 43 | } 44 | 45 | // An amount of memory that is greater than what is needed for static initialization 46 | // for any test we run. It was found experimentally on Ubuntu Linux 16.04 x86_64. 47 | static constexpr size_t STATIC_ALLOCATOR_SIZE = 0x800000; 48 | using osrf_testing_tools_cpp::memory_tools::impl::StaticAllocator; 49 | using StaticAllocatorT = StaticAllocator; 50 | static uint8_t g_static_allocator_storage[sizeof(StaticAllocatorT)]; 51 | 52 | // Contains global allocator to make 100% sure to avoid Static Initialization Order Fiasco. 53 | // "Construct on first use" idiom 54 | static StaticAllocatorT * 55 | get_static_allocator() 56 | { 57 | // placement-new the static allocator in preallocated storage 58 | // which is used while finding the original memory functions 59 | static StaticAllocatorT * alloc = new (g_static_allocator_storage) StaticAllocatorT; 60 | return alloc; 61 | } 62 | 63 | // storage for original malloc/realloc/calloc/free 64 | using MallocSignature = void * (*)(size_t); 65 | static MallocSignature g_original_malloc = nullptr; 66 | using ReallocSignature = void *(*)(void *, size_t); 67 | static ReallocSignature g_original_realloc = nullptr; 68 | using CallocSignature = void *(*)(size_t, size_t); 69 | static CallocSignature g_original_calloc = nullptr; 70 | using FreeSignature = void (*)(void *); 71 | static FreeSignature g_original_free = nullptr; 72 | 73 | // on shared library load, find and store the original memory function locations 74 | static __attribute__((constructor)) void __linux_memory_tools_init(void) 75 | { 76 | g_original_malloc = find_original_function("malloc"); 77 | g_original_realloc = find_original_function("realloc"); 78 | g_original_calloc = find_original_function("calloc"); 79 | g_original_free = find_original_function("free"); 80 | 81 | complete_static_initialization(); 82 | } 83 | 84 | extern "C" 85 | { 86 | 87 | void * 88 | malloc(size_t size) noexcept 89 | { 90 | if (!get_static_initialization_complete()) { 91 | return get_static_allocator()->allocate(size); 92 | } 93 | return unix_replacement_malloc(size, g_original_malloc); 94 | } 95 | 96 | void * 97 | realloc(void * pointer, size_t size) noexcept 98 | { 99 | if (!get_static_initialization_complete()) { 100 | return get_static_allocator()->reallocate(pointer, size); 101 | } 102 | return unix_replacement_realloc(pointer, size, g_original_realloc); 103 | } 104 | 105 | void * 106 | calloc(size_t count, size_t size) noexcept 107 | { 108 | if (!get_static_initialization_complete()) { 109 | return get_static_allocator()->zero_allocate(count, size); 110 | } 111 | return unix_replacement_calloc(count, size, g_original_calloc); 112 | } 113 | 114 | void 115 | free(void * pointer) noexcept 116 | { 117 | if (nullptr == pointer || get_static_allocator()->deallocate(pointer)) { 118 | // free of nullptr or, 119 | // memory was originally allocated by static allocator, no need to pass to "real" free 120 | return; 121 | } 122 | unix_replacement_free(pointer, g_original_free); 123 | } 124 | 125 | } // extern "C" 126 | 127 | #endif // defined(__linux__) 128 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/impl/static_allocator.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__IMPL__STATIC_ALLOCATOR_HPP_ 16 | #define MEMORY_TOOLS__IMPL__STATIC_ALLOCATOR_HPP_ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "../safe_fwrite.hpp" 24 | 25 | namespace osrf_testing_tools_cpp 26 | { 27 | namespace memory_tools 28 | { 29 | namespace impl 30 | { 31 | 32 | // Alignment of the largest primitive type for this system. 33 | static constexpr size_t MAX_ALIGN = alignof(std::max_align_t); 34 | 35 | /// Round value up to a multiple of alignment. 36 | /** 37 | * Implementation cribbed from Boost. 38 | * https://github.com/boostorg/align/blob/develop/include/boost/align/align_up.hpp 39 | */ 40 | static constexpr inline std::size_t 41 | align_up(std::size_t value, std::size_t alignment) noexcept 42 | { 43 | return (value + alignment - 1) & ~(alignment - 1); 44 | } 45 | 46 | template 47 | class StaticAllocator 48 | { 49 | public: 50 | StaticAllocator() 51 | : memory_pool_{0}, 52 | begin_(memory_pool_), 53 | end_(memory_pool_ + MemoryPoolSize), 54 | stack_pointer_(memory_pool_) 55 | { 56 | (void)memset(memory_pool_, 0x0, sizeof(memory_pool_)); 57 | } 58 | 59 | void * 60 | allocate(size_t size) 61 | { 62 | const size_t aligned_size = align_up(size, MAX_ALIGN); 63 | if (aligned_size <= static_cast(std::distance(end_, stack_pointer_))) { 64 | uint8_t * result = stack_pointer_; 65 | stack_pointer_ += aligned_size; 66 | return result; 67 | } 68 | SAFE_FWRITE(stderr, "StackAllocator.allocate() -> nullptr\n"); 69 | return nullptr; 70 | } 71 | 72 | void * 73 | reallocate(void * memory_in, size_t size) 74 | { 75 | if (!pointer_belongs_to_allocator(memory_in)) { 76 | SAFE_FWRITE(stderr, 77 | "StaticAllocator::reallocate(): asked to reallocate extra-allocator memory\n"); 78 | return nullptr; 79 | } 80 | void * memory = this->allocate(size); 81 | if (nullptr != memory) { 82 | // This would be an unsafe opertion, because memcpy would read beyond the 83 | // original size of memory_in in the case that size is bigger than the 84 | // original size requested for memory_in, but since we know memory_in 85 | // came from this static allocator and that we were able to allocate 86 | // more memory after memory_in, then we can know that while what comes 87 | // after memory_in might be unrelated or garbage, it will be safe to read 88 | // from that space. 89 | memcpy(memory, memory_in, size); 90 | this->deallocate(memory_in); 91 | } 92 | return memory; 93 | } 94 | 95 | void * 96 | zero_allocate(size_t count, size_t size) 97 | { 98 | size_t total_size = count * size; 99 | void * memory = this->allocate(total_size); 100 | if (nullptr != memory) { 101 | memset(memory, 0x0, total_size); 102 | } 103 | return memory; 104 | } 105 | 106 | bool 107 | pointer_belongs_to_allocator(const void * pointer) const 108 | { 109 | const uint8_t * typed_pointer = reinterpret_cast(pointer); 110 | return ( 111 | !(std::less()(typed_pointer, begin_)) && 112 | (std::less()(typed_pointer, end_)) 113 | ); 114 | } 115 | 116 | bool 117 | deallocate(void * pointer) 118 | { 119 | return this->pointer_belongs_to_allocator(pointer); 120 | } 121 | 122 | private: 123 | // Make sure that our memory pool is aligned to the maximum primitive size for this system. 124 | alignas(MAX_ALIGN) uint8_t memory_pool_[MemoryPoolSize]; 125 | uint8_t * begin_; 126 | uint8_t * end_; 127 | uint8_t * stack_pointer_; 128 | }; 129 | 130 | } // namespace impl 131 | } // namespace memory_tools 132 | } // namespace osrf_testing_tools_cpp 133 | 134 | #endif // MEMORY_TOOLS__IMPL__STATIC_ALLOCATOR_HPP_ 135 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/impl/unix_common.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "./unix_common.hpp" 16 | 17 | #include 18 | #include 19 | 20 | #include "../custom_memory_functions.hpp" 21 | #include "osrf_testing_tools_cpp/scope_exit.hpp" 22 | 23 | static bool g_static_initialization_complete = false; 24 | 25 | static std::recursive_mutex* g_memory_function_recursive_mutex; 26 | 27 | void 28 | complete_static_initialization() 29 | { 30 | g_memory_function_recursive_mutex = new std::recursive_mutex; 31 | g_static_initialization_complete = true; 32 | } 33 | 34 | bool & 35 | get_static_initialization_complete() 36 | { 37 | return g_static_initialization_complete; 38 | } 39 | 40 | static size_t g_inside_custom_memory_function = 0; 41 | 42 | extern "C" 43 | { 44 | 45 | void * 46 | unix_replacement_malloc(size_t size, void *(*original_malloc)(size_t)) 47 | { 48 | // Short-circuit to original function during self-recursion, if static initialization is done. 49 | if (!g_static_initialization_complete || 0 != g_inside_custom_memory_function) { 50 | return original_malloc(size); 51 | } 52 | std::lock_guard lock(*g_memory_function_recursive_mutex); 53 | g_inside_custom_memory_function++; 54 | OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ 55 | g_inside_custom_memory_function--; 56 | }); 57 | 58 | using osrf_testing_tools_cpp::memory_tools::custom_malloc_with_original; 59 | return custom_malloc_with_original(size, original_malloc, __func__, false); 60 | } 61 | 62 | void * 63 | unix_replacement_realloc(void * memory_in, size_t size, void *(*original_realloc)(void *, size_t)) 64 | { 65 | // Short-circuit to original function during self-recursion, if static initialization is done. 66 | if (!g_static_initialization_complete || 0 != g_inside_custom_memory_function) { 67 | return original_realloc(memory_in, size); 68 | } 69 | std::lock_guard lock(*g_memory_function_recursive_mutex); 70 | g_inside_custom_memory_function++; 71 | OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ 72 | g_inside_custom_memory_function--; 73 | }); 74 | 75 | using osrf_testing_tools_cpp::memory_tools::custom_realloc_with_original; 76 | return custom_realloc_with_original(memory_in, size, original_realloc, __func__, false); 77 | } 78 | 79 | void * 80 | unix_replacement_calloc(size_t count, size_t size, void *(*original_calloc)(size_t, size_t)) 81 | { 82 | // Short-circuit to original function during self-recursion, if static initialization is done. 83 | if (!g_static_initialization_complete || 0 != g_inside_custom_memory_function) { 84 | return original_calloc(count, size); 85 | } 86 | std::lock_guard lock(*g_memory_function_recursive_mutex); 87 | g_inside_custom_memory_function++; 88 | OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ 89 | g_inside_custom_memory_function--; 90 | }); 91 | 92 | using osrf_testing_tools_cpp::memory_tools::custom_calloc_with_original; 93 | return custom_calloc_with_original(count, size, original_calloc, __func__, false); 94 | } 95 | 96 | void 97 | unix_replacement_free(void * memory, void (*original_free)(void *)) 98 | { 99 | if (nullptr == memory) { 100 | return; 101 | } 102 | // Short-circuit to original function during self-recursion, if static initialization is done. 103 | if (!g_static_initialization_complete || 0 != g_inside_custom_memory_function) { 104 | return original_free(memory); 105 | } 106 | std::lock_guard lock(*g_memory_function_recursive_mutex); 107 | g_inside_custom_memory_function++; 108 | OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ 109 | g_inside_custom_memory_function--; 110 | }); 111 | 112 | using osrf_testing_tools_cpp::memory_tools::custom_free_with_original; 113 | custom_free_with_original(memory, original_free, __func__, false); 114 | } 115 | 116 | } // extern "C" 117 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/impl/unix_common.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__IMPL__UNIX_COMMON_HPP_ 16 | #define MEMORY_TOOLS__IMPL__UNIX_COMMON_HPP_ 17 | 18 | #include 19 | 20 | void 21 | complete_static_initialization(); 22 | 23 | bool & 24 | get_static_initialization_complete(); 25 | 26 | extern "C" 27 | { 28 | 29 | void * 30 | unix_replacement_malloc(size_t size, void *(*original_malloc)(size_t)); 31 | 32 | void * 33 | unix_replacement_realloc(void * memory_in, size_t size, void *(*original_realloc)(void *, size_t)); 34 | 35 | void * 36 | unix_replacement_calloc(size_t count, size_t size, void *(*original_calloc)(size_t, size_t)); 37 | 38 | void 39 | unix_replacement_free(void * memory, void (*original_free)(void *)); 40 | 41 | } // extern "C" 42 | 43 | #endif // MEMORY_TOOLS__IMPL__UNIX_COMMON_HPP_ 44 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/impl/unsupported_os.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "osrf_testing_tools_cpp/memory_tools/visibility_control.hpp" 16 | 17 | namespace osrf_testing_tools_cpp 18 | { 19 | namespace memory_tools 20 | { 21 | 22 | /// Function to ensure at least one symbol exists on Windows. 23 | OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_EXPORT 24 | void 25 | do_not_use() 26 | {} 27 | 28 | } // namespace memory_tools 29 | } // namespace osrf_testing_tools_cpp 30 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/implementation_monitoring_override.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "./implementation_monitoring_override.hpp" 16 | 17 | namespace osrf_testing_tools_cpp 18 | { 19 | namespace memory_tools 20 | { 21 | 22 | static bool g_inside_implementation = false; 23 | 24 | bool 25 | inside_implementation() 26 | { 27 | return g_inside_implementation; 28 | } 29 | 30 | void 31 | begin_implementation_section() 32 | { 33 | g_inside_implementation = true; 34 | } 35 | 36 | void 37 | end_implementation_section() 38 | { 39 | g_inside_implementation = false; 40 | } 41 | 42 | ScopedImplementationSection::ScopedImplementationSection() 43 | { 44 | begin_implementation_section(); 45 | } 46 | 47 | ScopedImplementationSection::~ScopedImplementationSection() 48 | { 49 | end_implementation_section(); 50 | } 51 | 52 | } // namespace memory_tools 53 | } // namespace osrf_testing_tools_cpp 54 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/implementation_monitoring_override.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__IMPLEMENTATION_MONITORING_OVERRIDE_HPP_ 16 | #define MEMORY_TOOLS__IMPLEMENTATION_MONITORING_OVERRIDE_HPP_ 17 | 18 | namespace osrf_testing_tools_cpp 19 | { 20 | namespace memory_tools 21 | { 22 | 23 | /// Return true if dynamic memory hooks should be avoided due to being inside implementation. 24 | bool 25 | inside_implementation(); 26 | 27 | /// Begin an implementation section, thread-specific. 28 | void 29 | begin_implementation_section(); 30 | 31 | /// End an implementation section, thread-specific. 32 | void 33 | end_implementation_section(); 34 | 35 | /// Scoped implementation context, thread-specific. 36 | /** 37 | * While this object is in scope, it's considered to be an implementation section. 38 | */ 39 | class ScopedImplementationSection 40 | { 41 | public: 42 | ScopedImplementationSection(); 43 | ~ScopedImplementationSection(); 44 | }; 45 | 46 | } // namespace memory_tools 47 | } // namespace osrf_testing_tools_cpp 48 | 49 | #endif // MEMORY_TOOLS__IMPLEMENTATION_MONITORING_OVERRIDE_HPP_ 50 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/initialize.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | 18 | #include "./custom_memory_functions.hpp" 19 | #include "osrf_testing_tools_cpp/memory_tools/initialize.hpp" 20 | #include "osrf_testing_tools_cpp/memory_tools/monitoring.hpp" 21 | #include "osrf_testing_tools_cpp/memory_tools/register_hooks.hpp" 22 | #include "osrf_testing_tools_cpp/memory_tools/testing_helpers.hpp" 23 | #include "osrf_testing_tools_cpp/memory_tools/verbosity.hpp" 24 | 25 | namespace osrf_testing_tools_cpp 26 | { 27 | namespace memory_tools 28 | { 29 | 30 | static std::atomic g_initialized(false); 31 | 32 | bool 33 | initialized() 34 | { 35 | return g_initialized.load(); 36 | } 37 | 38 | void 39 | initialize() 40 | { 41 | auto conditional_print = [](const char * msg) { 42 | if (get_verbosity_level() != VerbosityLevel::quiet) { 43 | SAFE_FWRITE(stdout, msg); 44 | } 45 | }; 46 | conditional_print("initializing memory tools...\n"); 47 | g_initialized.store(true); 48 | } 49 | 50 | bool 51 | uninitialize() 52 | { 53 | // reset settings 54 | unset_thread_specific_monitoring_enable(); 55 | disable_monitoring_in_all_threads(); 56 | on_malloc(nullptr); 57 | on_realloc(nullptr); 58 | on_calloc(nullptr); 59 | on_free(nullptr); 60 | expect_no_malloc_end(); 61 | expect_no_realloc_end(); 62 | expect_no_calloc_end(); 63 | expect_no_free_end(); 64 | return g_initialized.exchange(true); 65 | } 66 | 67 | } // namespace memory_tools 68 | } // namespace osrf_testing_tools_cpp 69 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/is_working.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "osrf_testing_tools_cpp/memory_tools/is_working.hpp" 16 | 17 | #include 18 | #include 19 | 20 | #include "osrf_testing_tools_cpp/memory_tools/register_hooks.hpp" 21 | 22 | namespace osrf_testing_tools_cpp 23 | { 24 | namespace memory_tools 25 | { 26 | 27 | volatile char side_effect[1024]; 28 | 29 | void 30 | guaranteed_malloc(const std::string & str) 31 | { 32 | void * some_memory = std::malloc(1024); 33 | // We need to do something with the malloc'ed memory to make sure this 34 | // function doesn't get optimized away. memset isn't enough, so we do a 35 | // memcpy from a passed in string, and then copy *that* out to an array that 36 | // is globally visible (assuring we have a side-effect). This is enough to 37 | // keep the optimizer away. 38 | memcpy(some_memory, str.c_str(), str.length()); 39 | memcpy((void *)side_effect, some_memory, str.length()); 40 | std::free(some_memory); 41 | } 42 | 43 | bool 44 | is_working() 45 | { 46 | auto original_on_malloc = get_on_malloc(); 47 | bool malloc_was_called = false; 48 | on_malloc([&]() {malloc_was_called = true;}); 49 | std::string tmp("doesn't matter"); 50 | guaranteed_malloc(tmp); 51 | on_malloc(original_on_malloc); 52 | return malloc_was_called; 53 | } 54 | 55 | } // namespace memory_tools 56 | } // namespace osrf_testing_tools_cpp 57 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/memory_tools.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #if defined(__linux__) && !defined(__ANDROID__) 16 | 17 | #include "./impl/linux.cpp" 18 | #include "./impl/unix_common.cpp" 19 | 20 | #elif defined(__APPLE__) 21 | 22 | #include "./impl/apple.cpp" 23 | #include "./impl/unix_common.cpp" 24 | 25 | // #elif defined(_WIN32) 26 | 27 | // TODO(wjwwood): install custom malloc (and others) for Windows. 28 | 29 | #else 30 | 31 | #include "./impl/unsupported_os.cpp" 32 | 33 | #endif // if defined(__linux__) elif defined(__APPLE__) elif defined(_WIN32) else ... 34 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/memory_tools_service.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "./memory_tools_service_impl.hpp" 20 | #include "./stack_trace_impl.hpp" 21 | #include "osrf_testing_tools_cpp/memory_tools/memory_tools_service.hpp" 22 | #include "osrf_testing_tools_cpp/memory_tools/verbosity.hpp" 23 | 24 | namespace osrf_testing_tools_cpp 25 | { 26 | namespace memory_tools 27 | { 28 | 29 | MemoryToolsService::MemoryToolsService( 30 | MemoryFunctionType memory_function_type, 31 | const char * source_function_name) 32 | : impl_(new MemoryToolsServiceImpl(memory_function_type, source_function_name)) 33 | { 34 | switch(get_verbosity_level()) { 35 | case VerbosityLevel::quiet: 36 | impl_->ignored = true; 37 | impl_->should_print_backtrace = false; 38 | break; 39 | case VerbosityLevel::debug: 40 | impl_->ignored = false; 41 | impl_->should_print_backtrace = false; 42 | break; 43 | case VerbosityLevel::trace: 44 | impl_->ignored = false; 45 | impl_->should_print_backtrace = true; 46 | break; 47 | default: 48 | throw std::logic_error("unexpected case for VerbosityLevel"); 49 | } 50 | } 51 | 52 | MemoryToolsService::~MemoryToolsService() 53 | {} 54 | 55 | MemoryFunctionType 56 | MemoryToolsService::get_memory_function_type() const 57 | { 58 | return impl_->memory_function_type; 59 | } 60 | 61 | const char * 62 | MemoryToolsService::get_memory_function_type_str() const 63 | { 64 | switch (impl_->memory_function_type) { 65 | case MemoryFunctionType::Malloc: 66 | return "malloc"; 67 | case MemoryFunctionType::Realloc: 68 | return "realloc"; 69 | case MemoryFunctionType::Calloc: 70 | return "calloc"; 71 | case MemoryFunctionType::Free: 72 | return "free"; 73 | default: 74 | throw std::runtime_error("unexpected default case in switch statement"); 75 | } 76 | } 77 | 78 | void 79 | MemoryToolsService::ignore() 80 | { 81 | impl_->ignored = true; 82 | } 83 | 84 | void 85 | MemoryToolsService::unignore() 86 | { 87 | impl_->ignored = false; 88 | } 89 | 90 | void 91 | MemoryToolsService::print_backtrace() 92 | { 93 | impl_->should_print_backtrace = true; 94 | } 95 | 96 | StackTrace * 97 | MemoryToolsService::get_stack_trace() 98 | { 99 | #if !defined(_WIN32) && !defined(__ANDROID__) 100 | if (nullptr == impl_->lazy_stack_trace) { 101 | backward::StackTrace st; 102 | st.load_here(256); 103 | impl_->lazy_stack_trace.reset(new StackTrace(std::unique_ptr( 104 | new StackTraceImpl(st, std::this_thread::get_id()) 105 | ))); 106 | } 107 | return impl_->lazy_stack_trace.get(); 108 | #else 109 | return nullptr; 110 | #endif // !defined(_WIN32) && !defined(__ANDROID__) 111 | } 112 | 113 | const char * 114 | MemoryToolsService::get_source_function_name() const 115 | { 116 | return impl_->source_function_name; 117 | } 118 | 119 | } // namespace memory_tools 120 | } // namespace osrf_testing_tools_cpp 121 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/memory_tools_service_factory.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_FACTORY_HPP_ 16 | #define MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_FACTORY_HPP_ 17 | 18 | #include "./memory_tools_service_impl.hpp" 19 | #include "osrf_testing_tools_cpp/memory_tools/memory_tools_service.hpp" 20 | 21 | namespace osrf_testing_tools_cpp 22 | { 23 | namespace memory_tools 24 | { 25 | 26 | class MemoryToolsServiceFactory 27 | { 28 | public: 29 | MemoryToolsServiceFactory( 30 | MemoryFunctionType memory_function_type, 31 | const char * source_function_name) 32 | : service_(memory_function_type, source_function_name) 33 | {} 34 | 35 | MemoryToolsService & 36 | get_memory_tools_service() 37 | { 38 | return service_; 39 | } 40 | 41 | bool 42 | should_ignore() 43 | { 44 | return !service_.impl_->should_print_backtrace && service_.impl_->ignored; 45 | } 46 | 47 | bool 48 | should_print_backtrace() 49 | { 50 | return service_.impl_->should_print_backtrace; 51 | } 52 | 53 | private: 54 | MemoryToolsService service_; 55 | }; 56 | 57 | } // namespace memory_tools 58 | } // namespace osrf_testing_tools_cpp 59 | 60 | #endif // MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_FACTORY_HPP_ 61 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/memory_tools_service_impl.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_IMPL_HPP_ 16 | #define MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_IMPL_HPP_ 17 | 18 | #include 19 | 20 | #include "osrf_testing_tools_cpp/memory_tools/memory_tools_service.hpp" 21 | 22 | namespace osrf_testing_tools_cpp 23 | { 24 | namespace memory_tools 25 | { 26 | 27 | class MemoryToolsServiceImpl 28 | { 29 | public: 30 | MemoryToolsServiceImpl( 31 | MemoryFunctionType memory_function_type_in, 32 | const char * source_function_name_in) 33 | : memory_function_type(memory_function_type_in), 34 | source_function_name(source_function_name_in), 35 | lazy_stack_trace(nullptr) 36 | {} 37 | 38 | MemoryFunctionType memory_function_type; 39 | const char * source_function_name; 40 | 41 | bool ignored; 42 | bool should_print_backtrace; 43 | std::unique_ptr lazy_stack_trace; 44 | }; 45 | 46 | } // namespace memory_tools 47 | } // namespace osrf_testing_tools_cpp 48 | 49 | #endif // MEMORY_TOOLS__MEMORY_TOOLS_SERVICE_IMPL_HPP_ 50 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/monitoring.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "osrf_testing_tools_cpp/memory_tools/monitoring.hpp" 16 | 17 | #include 18 | 19 | #include "./implementation_monitoring_override.hpp" 20 | #include "osrf_testing_tools_cpp/memory_tools/initialize.hpp" 21 | #include "osrf_testing_tools_cpp/scope_exit.hpp" 22 | 23 | namespace osrf_testing_tools_cpp 24 | { 25 | namespace memory_tools 26 | { 27 | 28 | static thread_local bool g_tls_thread_specific_enable_set = false; 29 | static thread_local bool g_tls_enabled = false; 30 | static std::atomic g_enabled(false); 31 | 32 | bool 33 | monitoring_enabled() 34 | { 35 | if ( 36 | !::osrf_testing_tools_cpp::memory_tools::initialized() || 37 | ::osrf_testing_tools_cpp::memory_tools::inside_implementation()) 38 | { 39 | return false; 40 | } 41 | if (g_tls_thread_specific_enable_set) { 42 | return g_tls_enabled; 43 | } else { 44 | return g_enabled.load(); 45 | } 46 | } 47 | 48 | void 49 | enable_monitoring() 50 | { 51 | g_tls_enabled = true; 52 | g_tls_thread_specific_enable_set = true; 53 | } 54 | 55 | void 56 | disable_monitoring() 57 | { 58 | g_tls_enabled = false; 59 | g_tls_thread_specific_enable_set = true; 60 | } 61 | 62 | void 63 | unset_thread_specific_monitoring_enable() 64 | { 65 | g_tls_enabled = false; 66 | g_tls_thread_specific_enable_set = false; 67 | } 68 | 69 | bool 70 | enable_monitoring_in_all_threads() 71 | { 72 | return g_enabled.exchange(true); 73 | } 74 | 75 | bool 76 | disable_monitoring_in_all_threads() 77 | { 78 | return g_enabled.exchange(false); 79 | } 80 | 81 | } // namespace memory_tools 82 | } // namespace osrf_testing_tools_cpp 83 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/print_backtrace.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__PRINT_BACKTRACE_HPP_ 16 | #define MEMORY_TOOLS__PRINT_BACKTRACE_HPP_ 17 | 18 | #if !defined(_WIN32) && !defined(__ANDROID__) 19 | 20 | # pragma GCC diagnostic push 21 | # ifdef __clang__ 22 | # pragma clang diagnostic ignored "-Wgnu-include-next" 23 | # pragma clang diagnostic ignored "-Wunused-parameter" 24 | # endif 25 | 26 | #include "./vendor/bombela/backward-cpp/backward.hpp" 27 | 28 | # pragma GCC diagnostic pop 29 | 30 | #endif // !defined(_WIN32) && !defined(__ANDROID__) 31 | 32 | namespace osrf_testing_tools_cpp 33 | { 34 | namespace memory_tools 35 | { 36 | 37 | template 38 | void 39 | print_backtrace(FILE * out = stderr) 40 | { 41 | #if !defined(_WIN32) && !defined(__ANDROID__) 42 | backward::StackTrace st; 43 | st.load_here(MaxStackDepth); 44 | backward::Printer p; 45 | p.print(st, out); 46 | #else 47 | fprintf(out, "backtrace unavailable on Windows and Android\n"); 48 | #endif // !defined(_WIN32) && !defined(__ANDROID__) 49 | } 50 | 51 | } // namespace memory_tools 52 | } // namespace osrf_testing_tools_cpp 53 | 54 | #endif // MEMORY_TOOLS__PRINT_BACKTRACE_HPP_ 55 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/register_hooks.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "./dispatch_callback.hpp" 16 | #include "./implementation_monitoring_override.hpp" 17 | #include "osrf_testing_tools_cpp/memory_tools/register_hooks.hpp" 18 | 19 | namespace osrf_testing_tools_cpp 20 | { 21 | namespace memory_tools 22 | { 23 | 24 | static std::atomic g_on_malloc_callback(nullptr); 25 | static std::atomic g_on_realloc_callback(nullptr); 26 | static std::atomic g_on_calloc_callback(nullptr); 27 | static std::atomic g_on_free_callback(nullptr); 28 | 29 | void 30 | on_malloc(AnyMemoryToolsCallback callback) 31 | { 32 | // prevents new from triggering existing hooks 33 | ScopedImplementationSection implementation_section; 34 | // duplicate user callback and then delete the old one 35 | auto old = g_on_malloc_callback.exchange(new AnyMemoryToolsCallback(callback)); 36 | if (nullptr != old) { 37 | delete old; 38 | } 39 | } 40 | 41 | AnyMemoryToolsCallback 42 | get_on_malloc() 43 | { 44 | auto current = g_on_malloc_callback.load(); 45 | if (current) { 46 | return *current; 47 | } 48 | return nullptr; 49 | } 50 | 51 | void 52 | dispatch_malloc(MemoryToolsService & service) 53 | { 54 | dispatch_callback(g_on_malloc_callback.load(), service); 55 | } 56 | 57 | void 58 | on_realloc(AnyMemoryToolsCallback callback) 59 | { 60 | // prevents new from triggering existing hooks 61 | ScopedImplementationSection implementation_section; 62 | // duplicate user callback and then delete the old one 63 | delete g_on_realloc_callback.exchange(new AnyMemoryToolsCallback(callback)); 64 | } 65 | 66 | AnyMemoryToolsCallback 67 | get_on_realloc() 68 | { 69 | auto current = g_on_realloc_callback.load(); 70 | if (current) { 71 | return *current; 72 | } 73 | return nullptr; 74 | } 75 | 76 | void 77 | dispatch_realloc(MemoryToolsService & service) 78 | { 79 | dispatch_callback(g_on_realloc_callback.load(), service); 80 | } 81 | 82 | void 83 | on_calloc(AnyMemoryToolsCallback callback) 84 | { 85 | // prevents new from triggering existing hooks 86 | ScopedImplementationSection implementation_section; 87 | // duplicate user callback and then delete the old one 88 | delete g_on_calloc_callback.exchange(new AnyMemoryToolsCallback(callback)); 89 | } 90 | 91 | AnyMemoryToolsCallback 92 | get_on_calloc() 93 | { 94 | auto current = g_on_calloc_callback.load(); 95 | if (current) { 96 | return *current; 97 | } 98 | return nullptr; 99 | } 100 | 101 | void 102 | dispatch_calloc(MemoryToolsService & service) 103 | { 104 | dispatch_callback(g_on_calloc_callback.load(), service); 105 | } 106 | 107 | void 108 | on_free(AnyMemoryToolsCallback callback) 109 | { 110 | // prevents new from triggering existing hooks 111 | ScopedImplementationSection implementation_section; 112 | // duplicate user callback and then delete the old one 113 | delete g_on_free_callback.exchange(new AnyMemoryToolsCallback(callback)); 114 | } 115 | 116 | AnyMemoryToolsCallback 117 | get_on_free() 118 | { 119 | auto current = g_on_free_callback.load(); 120 | if (current) { 121 | return *current; 122 | } 123 | return nullptr; 124 | } 125 | 126 | void 127 | dispatch_free(MemoryToolsService & service) 128 | { 129 | dispatch_callback(g_on_free_callback.load(), service); 130 | } 131 | 132 | } // namespace memory_tools 133 | } // namespace osrf_testing_tools_cpp 134 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/safe_fwrite.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MEMORY_TOOLS__SAFE_FWRITE_HPP_ 16 | #define MEMORY_TOOLS__SAFE_FWRITE_HPP_ 17 | 18 | #include 19 | #include 20 | 21 | #if defined(_WIN32) 22 | // Limit the buffer size in the `fwrite` call to give an upper bound to buffer overrun in the case 23 | // of non-null terminated `msg`. 24 | #define SAFE_FWRITE(out, msg) fwrite(msg, sizeof(char), strnlen_s(msg, 4096), out) 25 | #else 26 | #define SAFE_FWRITE(out, msg) fwrite(msg, sizeof(char), strlen(msg), out) 27 | #endif 28 | 29 | #endif // MEMORY_TOOLS__SAFE_FWRITE_HPP_ 30 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/stack_trace.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "osrf_testing_tools_cpp/memory_tools/stack_trace.hpp" 16 | 17 | #include "./stack_trace_impl.hpp" 18 | 19 | namespace osrf_testing_tools_cpp 20 | { 21 | namespace memory_tools 22 | { 23 | 24 | SourceLocation::SourceLocation(std::shared_ptr impl) 25 | : impl_(std::move(impl)) 26 | {} 27 | 28 | SourceLocation::~SourceLocation() 29 | {} 30 | 31 | const std::string & 32 | SourceLocation::function() const 33 | { 34 | #if !defined(_WIN32) && !defined(__ANDROID__) 35 | return impl_->source_location->function; 36 | #else 37 | throw std::runtime_error("not implemented on Windows or Android"); 38 | #endif 39 | } 40 | 41 | const std::string & 42 | SourceLocation::filename() const 43 | { 44 | #if !defined(_WIN32) && !defined(__ANDROID__) 45 | return impl_->source_location->filename; 46 | #else 47 | throw std::runtime_error("not implemented on Windows or Android"); 48 | #endif 49 | } 50 | 51 | size_t 52 | SourceLocation::line() const 53 | { 54 | #if !defined(_WIN32) && !defined(__ANDROID__) 55 | return impl_->source_location->line; 56 | #else 57 | throw std::runtime_error("not implemented on Windows or Android"); 58 | #endif 59 | } 60 | 61 | size_t 62 | SourceLocation::column() const 63 | { 64 | #if !defined(_WIN32) && !defined(__ANDROID__) 65 | return impl_->source_location->col; 66 | #else 67 | throw std::runtime_error("not implemented on Windows or Android"); 68 | #endif 69 | } 70 | 71 | Trace::Trace(std::unique_ptr impl) 72 | : impl_(std::move(impl)) 73 | {} 74 | 75 | Trace::Trace(const Trace & other) 76 | : impl_(new TraceImpl(*other.impl_)) 77 | {} 78 | 79 | Trace::~Trace() 80 | {} 81 | 82 | void * 83 | Trace::address() const 84 | { 85 | #if !defined(_WIN32) && !defined(__ANDROID__) 86 | return impl_->resolved_trace.addr; 87 | #else 88 | throw std::runtime_error("not implemented on Windows or Android"); 89 | #endif 90 | } 91 | 92 | size_t 93 | Trace::index_in_stack() const 94 | { 95 | #if !defined(_WIN32) && !defined(__ANDROID__) 96 | return impl_->resolved_trace.idx; 97 | #else 98 | throw std::runtime_error("not implemented on Windows or Android"); 99 | #endif 100 | } 101 | 102 | const std::string & 103 | Trace::object_filename() const 104 | { 105 | #if !defined(_WIN32) && !defined(__ANDROID__) 106 | return impl_->resolved_trace.object_filename; 107 | #else 108 | throw std::runtime_error("not implemented on Windows or Android"); 109 | #endif 110 | } 111 | 112 | const std::string & 113 | Trace::object_function() const 114 | { 115 | #if !defined(_WIN32) && !defined(__ANDROID__) 116 | return impl_->resolved_trace.object_function; 117 | #else 118 | throw std::runtime_error("not implemented on Windows or Android"); 119 | #endif 120 | } 121 | 122 | const SourceLocation & 123 | Trace::source_location() const 124 | { 125 | #if !defined(_WIN32) && !defined(__ANDROID__) 126 | return impl_->source_location; 127 | #else 128 | throw std::runtime_error("not implemented on Windows or Android"); 129 | #endif 130 | } 131 | 132 | const std::vector & 133 | Trace::inlined_source_locations() const 134 | { 135 | #if !defined(_WIN32) && !defined(__ANDROID__) 136 | return impl_->inlined_source_locations; 137 | #else 138 | throw std::runtime_error("not implemented on Windows or Android"); 139 | #endif 140 | } 141 | 142 | StackTrace::StackTrace(std::unique_ptr impl) 143 | : impl_(std::move(impl)) 144 | {} 145 | 146 | StackTrace::~StackTrace() 147 | {} 148 | 149 | std::thread::id 150 | StackTrace::thread_id() const 151 | { 152 | #if !defined(_WIN32) && !defined(__ANDROID__) 153 | return impl_->thread_id; 154 | #else 155 | throw std::runtime_error("not implemented on Windows or Android"); 156 | #endif 157 | } 158 | 159 | const std::vector & 160 | StackTrace::get_traces() const 161 | { 162 | #if !defined(_WIN32) && !defined(__ANDROID__) 163 | return impl_->traces; 164 | #else 165 | throw std::runtime_error("not implemented on Windows or Android"); 166 | #endif 167 | } 168 | 169 | std::vector 170 | StackTrace::get_traces_from_function_name(const char * function_name) const 171 | { 172 | #if !defined(_WIN32) && !defined(__ANDROID__) 173 | std::vector result; 174 | bool function_found = false; 175 | for (const Trace & trace : impl_->traces) { 176 | if (!function_found && trace.object_function().find(function_name) == 0) { 177 | function_found = true; 178 | } 179 | if (function_found) { 180 | result.emplace_back(trace); 181 | } 182 | } 183 | return result; 184 | #else 185 | (void) function_name; 186 | throw std::runtime_error("not implemented on Windows or Android"); 187 | #endif 188 | } 189 | 190 | } // namespace memory_tools 191 | } // namespace osrf_testing_tools_cpp 192 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/stack_trace_impl.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef OSRF_TESTING_TOOLS_CPP__STACK_TRACE_IMPL_HPP_ 16 | #define OSRF_TESTING_TOOLS_CPP__STACK_TRACE_IMPL_HPP_ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "osrf_testing_tools_cpp/memory_tools/stack_trace.hpp" 23 | 24 | #if !defined(_WIN32) && !defined(__ANDROID__) 25 | 26 | #pragma GCC diagnostic push 27 | #ifdef __clang__ 28 | # pragma clang diagnostic ignored "-Wgnu-include-next" 29 | # pragma clang diagnostic ignored "-Wunused-parameter" 30 | #endif 31 | #include "./vendor/bombela/backward-cpp/backward.hpp" 32 | #pragma GCC diagnostic pop 33 | 34 | namespace osrf_testing_tools_cpp 35 | { 36 | namespace memory_tools 37 | { 38 | 39 | struct SourceLocationImpl 40 | { 41 | SourceLocationImpl() = delete; 42 | explicit SourceLocationImpl(const backward::ResolvedTrace::SourceLoc * sl) 43 | : source_location(sl) 44 | {} 45 | 46 | virtual ~SourceLocationImpl() {} 47 | 48 | const backward::ResolvedTrace::SourceLoc * source_location; 49 | }; 50 | 51 | struct TraceImpl 52 | { 53 | TraceImpl() = delete; 54 | 55 | TraceImpl(backward::TraceResolver * trace_resolver, const backward::Trace & trace) 56 | : TraceImpl(trace_resolver->resolve(trace)) 57 | {} 58 | 59 | TraceImpl(const TraceImpl & other) 60 | : TraceImpl(other.resolved_trace) 61 | {} 62 | 63 | explicit TraceImpl(backward::ResolvedTrace resolved_trace_input) 64 | : resolved_trace(resolved_trace_input), 65 | source_location( 66 | std::unique_ptr(new SourceLocationImpl(&resolved_trace.source))) 67 | { 68 | inlined_source_locations.reserve(resolved_trace.inliners.size()); 69 | for (const auto & inliner : resolved_trace.inliners) { 70 | inlined_source_locations.emplace_back( 71 | std::shared_ptr(new SourceLocationImpl(&inliner)) 72 | ); 73 | } 74 | } 75 | 76 | virtual ~TraceImpl() {} 77 | 78 | backward::ResolvedTrace resolved_trace; 79 | SourceLocation source_location; 80 | std::vector inlined_source_locations; 81 | }; 82 | 83 | struct StackTraceImpl 84 | { 85 | StackTraceImpl() = delete; 86 | explicit StackTraceImpl(backward::StackTrace st, std::thread::id tid) 87 | : stack_trace(st), thread_id(tid) 88 | { 89 | trace_resolver.load_stacktrace(stack_trace); 90 | traces.reserve(stack_trace.size()); 91 | for (size_t i = 0; i < stack_trace.size(); ++i) { 92 | std::unique_ptr tmp(new TraceImpl(&trace_resolver, stack_trace[i])); 93 | traces.emplace_back( 94 | std::move(tmp) 95 | ); 96 | } 97 | } 98 | 99 | virtual ~StackTraceImpl() {} 100 | 101 | backward::StackTrace stack_trace; 102 | std::thread::id thread_id; 103 | backward::TraceResolver trace_resolver; 104 | std::vector traces; 105 | }; 106 | 107 | } // namespace memory_tools 108 | } // namespace osrf_testing_tools_cpp 109 | 110 | #else 111 | 112 | namespace osrf_testing_tools_cpp 113 | { 114 | namespace memory_tools 115 | { 116 | 117 | struct SourceLocationImpl {}; 118 | 119 | struct TraceImpl {}; 120 | 121 | struct StackTraceImpl {}; 122 | 123 | } // namespace memory_tools 124 | } // namespace osrf_testing_tools_cpp 125 | 126 | #endif // !defined(_WIN32) && !defined(__ANDROID__) 127 | 128 | #endif // OSRF_TESTING_TOOLS_CPP__STACK_TRACE_IMPL_HPP_ 129 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/test_count_function_in_backtrace.cpp: -------------------------------------------------------------------------------- 1 | void func(); 2 | 3 | int main(void) 4 | { 5 | func(); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/test_lib.cpp: -------------------------------------------------------------------------------- 1 | #include "./count_function_occurrences_in_backtrace.hpp" 2 | 3 | void func() 4 | { 5 | printf("entering func()\n"); 6 | static size_t recurse_count = 0; 7 | if ( 8 | recurse_count++ < 10 && 9 | osrf_testing_tools_cpp::memory_tools::count_function_occurrences_in_backtrace(func) <= 2) 10 | { 11 | func(); 12 | } 13 | printf("exiting func(%zu)\n", recurse_count); 14 | } 15 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/testing_helpers.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "./dispatch_callback.hpp" 16 | #include "osrf_testing_tools_cpp/memory_tools/register_hooks.hpp" 17 | #include "osrf_testing_tools_cpp/memory_tools/testing_helpers.hpp" 18 | 19 | namespace osrf_testing_tools_cpp 20 | { 21 | namespace memory_tools 22 | { 23 | 24 | static std::atomic g_malloc_unexpected(false); 25 | static std::atomic g_realloc_unexpected(false); 26 | static std::atomic g_calloc_unexpected(false); 27 | static std::atomic g_free_unexpected(false); 28 | 29 | void 30 | on_unexpected_malloc(AnyMemoryToolsCallback callback) 31 | { 32 | on_malloc( 33 | [callback](MemoryToolsService & service) { 34 | if (g_malloc_unexpected.load()) { 35 | service.unignore(); 36 | dispatch_callback(&callback, service); 37 | } 38 | }); 39 | } 40 | 41 | bool 42 | malloc_expected() 43 | { 44 | return !g_malloc_unexpected.load(); 45 | } 46 | 47 | void 48 | expect_no_malloc_begin() 49 | { 50 | g_malloc_unexpected.store(true); 51 | } 52 | 53 | void 54 | expect_no_malloc_end() 55 | { 56 | g_malloc_unexpected.store(false); 57 | } 58 | 59 | void 60 | on_unexpected_realloc(AnyMemoryToolsCallback callback) 61 | { 62 | on_realloc( 63 | [callback](MemoryToolsService & service) { 64 | if (g_realloc_unexpected.load()) { 65 | service.unignore(); 66 | dispatch_callback(&callback, service); 67 | } 68 | }); 69 | } 70 | 71 | bool 72 | realloc_expected() 73 | { 74 | return !g_realloc_unexpected.load(); 75 | } 76 | 77 | void 78 | expect_no_realloc_begin() 79 | { 80 | g_realloc_unexpected.store(true); 81 | } 82 | 83 | void 84 | expect_no_realloc_end() 85 | { 86 | g_realloc_unexpected.store(false); 87 | } 88 | 89 | void 90 | on_unexpected_calloc(AnyMemoryToolsCallback callback) 91 | { 92 | on_calloc( 93 | [callback](MemoryToolsService & service) { 94 | if (g_calloc_unexpected.load()) { 95 | service.unignore(); 96 | dispatch_callback(&callback, service); 97 | } 98 | }); 99 | } 100 | 101 | bool 102 | calloc_expected() 103 | { 104 | return !g_calloc_unexpected.load(); 105 | } 106 | 107 | void 108 | expect_no_calloc_begin() 109 | { 110 | g_calloc_unexpected.store(true); 111 | } 112 | 113 | void 114 | expect_no_calloc_end() 115 | { 116 | g_calloc_unexpected.store(false); 117 | } 118 | 119 | void 120 | on_unexpected_free(AnyMemoryToolsCallback callback) 121 | { 122 | on_free( 123 | [callback](MemoryToolsService & service) { 124 | if (g_free_unexpected.load()) { 125 | service.unignore(); 126 | dispatch_callback(&callback, service); 127 | } 128 | }); 129 | } 130 | 131 | bool 132 | free_expected() 133 | { 134 | return !g_free_unexpected.load(); 135 | } 136 | 137 | void 138 | expect_no_free_begin() 139 | { 140 | g_free_unexpected.store(true); 141 | } 142 | 143 | void 144 | expect_no_free_end() 145 | { 146 | g_free_unexpected.store(false); 147 | } 148 | 149 | } // namespace memory_tools 150 | } // namespace osrf_testing_tools_cpp 151 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | *.pyc 3 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: 3 | - gcc 4 | - clang 5 | 6 | addons: 7 | apt: 8 | packages: 9 | - valgrind 10 | 11 | install: 12 | - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" 13 | - mkdir ${DEPS_DIR} && cd ${DEPS_DIR} 14 | - CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz" 15 | - mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake 16 | - export PATH=${DEPS_DIR}/cmake/bin:${PATH} 17 | - pip install --user conan && export PATH=$PATH:$HOME/.local/bin 18 | - cd ${TRAVIS_BUILD_DIR} 19 | - mkdir build && cd build 20 | - cmake .. -DBACKWARD_TESTS=ON 21 | - cmake --build . 22 | 23 | script: 24 | - valgrind ctest .. --verbose 25 | - cd ${TRAVIS_BUILD_DIR} && conan create . Manu343726/testing --build=outdated 26 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt 3 | # Copyright 2013 Google Inc. All Rights Reserved. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | cmake_minimum_required(VERSION 3.0) 24 | project(backward CXX) 25 | 26 | # Introduce variables: 27 | # * CMAKE_INSTALL_LIBDIR 28 | # * CMAKE_INSTALL_BINDIR 29 | # * CMAKE_INSTALL_INCLUDEDIR 30 | include(GNUInstallDirs) 31 | 32 | include(BackwardConfig.cmake) 33 | 34 | # check if compiler is nvcc or nvcc_wrapper 35 | set(COMPILER_IS_NVCC false) 36 | get_filename_component(COMPILER_NAME ${CMAKE_CXX_COMPILER} NAME) 37 | if (COMPILER_NAME MATCHES "^nvcc") 38 | set(COMPILER_IS_NVCC true) 39 | endif() 40 | 41 | if (DEFINED ENV{OMPI_CXX} OR DEFINED ENV{MPICH_CXX}) 42 | if ( ($ENV{OMPI_CXX} MATCHES "nvcc") OR ($ENV{MPICH_CXX} MATCHES "nvcc") ) 43 | set(COMPILER_IS_NVCC true) 44 | endif() 45 | endif() 46 | 47 | # set CXX standard 48 | set(CMAKE_CXX_STANDARD_REQUIRED True) 49 | set(CMAKE_CXX_STANDARD 11) 50 | if (${COMPILER_IS_NVCC}) 51 | # GNU CXX extensions are not supported by nvcc 52 | set(CMAKE_CXX_EXTENSIONS OFF) 53 | endif() 54 | 55 | ############################################################################### 56 | # COMPILER FLAGS 57 | ############################################################################### 58 | 59 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCXX) 60 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") 61 | if (NOT ${COMPILER_IS_NVCC}) 62 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic-errors") 63 | endif() 64 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") 65 | endif() 66 | 67 | ############################################################################### 68 | # BACKWARD OBJECT 69 | ############################################################################### 70 | 71 | add_library(backward_object OBJECT backward.cpp) 72 | target_compile_definitions(backward_object PRIVATE ${BACKWARD_DEFINITIONS}) 73 | target_include_directories(backward_object PRIVATE ${BACKWARD_INCLUDE_DIRS}) 74 | set(BACKWARD_ENABLE $ CACHE STRING 75 | "Link with this object to setup backward automatically") 76 | 77 | 78 | ############################################################################### 79 | # BACKWARD LIBRARY (Includes backward.cpp) 80 | ############################################################################### 81 | option(BACKWARD_SHARED "Build dynamic backward-cpp shared lib" OFF) 82 | 83 | if(BACKWARD_SHARED) 84 | set(libtype SHARED) 85 | endif() 86 | add_library(backward ${libtype} backward.cpp) 87 | target_compile_definitions(backward PUBLIC ${BACKWARD_DEFINITIONS}) 88 | target_include_directories(backward PUBLIC ${BACKWARD_INCLUDE_DIRS}) 89 | 90 | ############################################################################### 91 | # TESTS 92 | ############################################################################### 93 | 94 | if(BACKWARD_TESTS) 95 | enable_testing() 96 | 97 | add_library(test_main OBJECT test/_test_main.cpp) 98 | 99 | macro(backward_add_test src) 100 | get_filename_component(name ${src} NAME_WE) 101 | set(test_name "test_${name}") 102 | 103 | add_executable(${test_name} ${src} ${ARGN} $) 104 | 105 | target_link_libraries(${test_name} PRIVATE Backward::Backward) 106 | 107 | add_test(NAME ${name} COMMAND ${test_name}) 108 | endmacro() 109 | 110 | # Tests without backward.cpp 111 | set(TESTS 112 | test 113 | stacktrace 114 | rectrace 115 | select_signals 116 | ) 117 | 118 | foreach(test ${TESTS}) 119 | backward_add_test(test/${test}.cpp) 120 | endforeach() 121 | 122 | # Tests with backward.cpp 123 | set(TESTS 124 | suicide 125 | ) 126 | 127 | foreach(test ${TESTS}) 128 | backward_add_test(test/${test}.cpp ${BACKWARD_ENABLE}) 129 | endforeach() 130 | endif() 131 | 132 | install( 133 | FILES "backward.hpp" 134 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 135 | ) 136 | install( 137 | FILES "BackwardConfig.cmake" 138 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/backward 139 | ) 140 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2013 Google Inc. All Rights Reserved. 2 | 3 | The MIT License (MIT) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/backward.cpp: -------------------------------------------------------------------------------- 1 | // Pick your poison. 2 | // 3 | // On GNU/Linux, you have few choices to get the most out of your stack trace. 4 | // 5 | // By default you get: 6 | // - object filename 7 | // - function name 8 | // 9 | // In order to add: 10 | // - source filename 11 | // - line and column numbers 12 | // - source code snippet (assuming the file is accessible) 13 | 14 | // Install one of the following libraries then uncomment one of the macro (or 15 | // better, add the detection of the lib and the macro definition in your build 16 | // system) 17 | 18 | // - apt-get install libdw-dev ... 19 | // - g++/clang++ -ldw ... 20 | // #define BACKWARD_HAS_DW 1 21 | 22 | // - apt-get install binutils-dev ... 23 | // - g++/clang++ -lbfd ... 24 | // #define BACKWARD_HAS_BFD 1 25 | 26 | // - apt-get install libdwarf-dev ... 27 | // - g++/clang++ -ldwarf ... 28 | // #define BACKWARD_HAS_DWARF 1 29 | 30 | // Regardless of the library you choose to read the debug information, 31 | // for potentially more detailed stack traces you can use libunwind 32 | // - apt-get install libunwind-dev 33 | // - g++/clang++ -lunwind 34 | // #define BACKWARD_HAS_LIBUNWIND 1 35 | 36 | #include "backward.hpp" 37 | 38 | namespace backward { 39 | 40 | backward::SignalHandling sh; 41 | 42 | } // namespace backward 43 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/builds.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | COMPILERS_CXX98=`cat</dev/null 28 | ( 29 | cd "$builddir" 30 | cmake -DCMAKE_BUILD_TYPE=$buildtype -DBACKWARD_TESTS=ON .. 31 | ) 32 | } 33 | 34 | function build() { 35 | local builddir=$1 36 | shift 37 | make -C "$builddir" $@ 38 | } 39 | 40 | function dotest() { 41 | local builddir=$1 42 | shift 43 | make -C "$builddir" test $@ 44 | return 0 45 | } 46 | 47 | function do_action() { 48 | local lang=$1 49 | local action=$2 50 | shift 2 51 | 52 | for compiler in $COMPILERS; do 53 | local builddir="build_${lang}_${compiler}" 54 | 55 | if [[ $action == "cmake" ]]; then 56 | buildtype=$1 57 | mkbuild $compiler $lang "$buildtype" "$builddir" 58 | [[ $? != 0 ]] && exit 59 | elif [[ $action == "make" ]]; then 60 | build "$builddir" $@ 61 | [[ $? != 0 ]] && exit 62 | elif [[ $action == "test" ]]; then 63 | dotest "$builddir" $@ 64 | [[ $? != 0 ]] && exit 65 | elif [[ $action == "clean" ]]; then 66 | rm -r "$builddir" 67 | else 68 | echo "usage: $0 cmake [debug|release|relwithdbg]|make|test|clean" 69 | exit 255 70 | fi 71 | done 72 | } 73 | 74 | COMPILERS=$COMPILERS_CXX98 75 | do_action c++98 $@ 76 | COMPILERS=$COMPILERS_CXX11 77 | do_action c++11 $@ 78 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/conanfile.py: -------------------------------------------------------------------------------- 1 | from conans import ConanFile, CMake 2 | import os 3 | 4 | class BackwardCpp(ConanFile): 5 | settings = 'os', 'compiler', 'build_type', 'arch' 6 | name = 'backward' 7 | url = 'https://github.com/bombela/backward-cpp' 8 | license = 'MIT' 9 | version = '1.3.0' 10 | options = { 11 | 'stack_walking_unwind': [True, False], 12 | 'stack_walking_backtrace': [True, False], 13 | 'stack_details_auto_detect': [True, False], 14 | 'stack_details_backtrace_symbol': [True, False], 15 | 'stack_details_dw': [True, False], 16 | 'stack_details_bfd': [True, False], 17 | 'shared': [True, False] 18 | } 19 | default_options = ( 20 | 'stack_walking_unwind=True', 21 | 'stack_walking_backtrace=False', 22 | 'stack_details_auto_detect=True', 23 | 'stack_details_backtrace_symbol=False', 24 | 'stack_details_dw=False', 25 | 'stack_details_bfd=False', 26 | 'shared=False' 27 | ) 28 | exports = 'backward.cpp', 'backward.hpp', 'test/*', 'CMakeLists.txt', 'BackwardConfig.cmake' 29 | generators = 'cmake' 30 | 31 | def build(self): 32 | cmake = CMake(self) 33 | 34 | cmake.configure(defs={'BACKWARD_' + name.upper(): value for name, value in self.options.values.as_list()}) 35 | cmake.build() 36 | 37 | def package(self): 38 | self.copy('backward.hpp', os.path.join('include', 'backward')) 39 | self.copy('*.a', dst='lib') 40 | self.copy('*.so', dst='lib') 41 | self.copy('*.lib', dst='lib') 42 | self.copy('*.dll', dst='lib') 43 | 44 | def package_info(self): 45 | self.cpp_info.libs = ['backward'] 46 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/doc/nice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrf/osrf_testing_tools_cpp/748de1c14a5175e7727973761d53941adf26311c/osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/doc/nice.png -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/doc/pretty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrf/osrf_testing_tools_cpp/748de1c14a5175e7727973761d53941adf26311c/osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/doc/pretty.png -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/doc/rude.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrf/osrf_testing_tools_cpp/748de1c14a5175e7727973761d53941adf26311c/osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/doc/rude.png -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test/_test_main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * _test_main.cpp 3 | * Copyright 2013 Google Inc. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "test.hpp" 25 | #include 26 | #include 27 | 28 | #ifdef _WIN32 29 | #include 30 | #define strcasecmp _stricmp 31 | #else 32 | #include 33 | #include 34 | #endif 35 | 36 | #if defined(__has_include) && __has_include() 37 | #include 38 | #else 39 | #include 40 | 41 | #ifdef _WIN32 42 | char argv0[MAX_PATH]; 43 | inline const char *getprogname() { 44 | return GetModuleFileName(NULL, argv0, sizeof(argv0)) ? argv0 : NULL; 45 | } 46 | #elif !defined(__APPLE__) 47 | // N.B. getprogname() is an Apple/BSD-ism. 48 | // program_invocation_name is a GLIBC-ism, but it's also 49 | // supported by libmusl. 50 | #define getprogname() program_invocation_name 51 | #endif 52 | 53 | void error(int status, int errnum, const char *format, ...) { 54 | fflush(stdout); 55 | fprintf(stderr, "%s: ", getprogname()); 56 | 57 | va_list args; 58 | va_start(args, format); 59 | vfprintf(stderr, format, args); 60 | va_end(args); 61 | 62 | if (errnum != 0) { 63 | fprintf(stderr, ": %s\n", strerror(errnum)); 64 | } else { 65 | fprintf(stderr, "\n"); 66 | } 67 | if (status != 0) { 68 | exit(status); 69 | } 70 | } 71 | #endif 72 | 73 | using namespace test; 74 | 75 | bool run_test(TestBase &test, bool use_child_process = true) { 76 | if (!use_child_process) { 77 | exit(static_cast(test.run())); 78 | } 79 | 80 | printf("-- running test case: %s\n", test.name); 81 | 82 | fflush(stdout); 83 | 84 | test::TestStatus status = test::SUCCESS; 85 | 86 | #ifdef _WIN32 87 | char filename[256]; 88 | GetModuleFileName(NULL, filename, 256); // TODO: check for error 89 | std::string cmd_line = filename; 90 | cmd_line += " --nofork "; 91 | cmd_line += test.name; 92 | 93 | STARTUPINFO si; 94 | PROCESS_INFORMATION pi; 95 | ZeroMemory(&si, sizeof(si)); 96 | si.cb = sizeof(si); 97 | ZeroMemory(&pi, sizeof(pi)); 98 | 99 | if (!CreateProcessA(nullptr, const_cast(cmd_line.c_str()), nullptr, 100 | nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) { 101 | printf("unable to create process\n"); 102 | exit(-1); 103 | } 104 | 105 | WaitForSingleObject(pi.hProcess, INFINITE); 106 | 107 | DWORD exit_code; 108 | GetExitCodeProcess(pi.hProcess, &exit_code); 109 | switch (exit_code) { 110 | case 3: 111 | status = test::SIGNAL_ABORT; 112 | break; 113 | case 5: 114 | status = test::EXCEPTION_UNCAUGHT; 115 | break; 116 | case EXCEPTION_ACCESS_VIOLATION: 117 | status = test::SIGNAL_SEGFAULT; 118 | break; 119 | case EXCEPTION_STACK_OVERFLOW: 120 | status = test::SIGNAL_SEGFAULT; 121 | break; 122 | case EXCEPTION_INT_DIVIDE_BY_ZERO: 123 | status = test::SIGNAL_DIVZERO; 124 | break; 125 | } 126 | printf("Exit code: %lu\n", exit_code); 127 | 128 | CloseHandle(pi.hProcess); 129 | CloseHandle(pi.hThread); 130 | 131 | if (test.expected_status == test::ASSERT_FAIL) { 132 | // assert calls abort on windows 133 | return (status & test::SIGNAL_ABORT); 134 | } 135 | 136 | #else 137 | 138 | pid_t child_pid = fork(); 139 | if (child_pid == 0) { 140 | exit(static_cast(test.run())); 141 | } 142 | if (child_pid == -1) { 143 | error(EXIT_FAILURE, 0, "unable to fork"); 144 | } 145 | 146 | int child_status = 0; 147 | waitpid(child_pid, &child_status, 0); 148 | 149 | if (WIFEXITED(child_status)) { 150 | int exit_status = WEXITSTATUS(child_status); 151 | if (exit_status & ~test::STATUS_MASK) { 152 | status = test::FAILED; 153 | } else { 154 | status = static_cast(exit_status); 155 | } 156 | } else if (WIFSIGNALED(child_status)) { 157 | const int signum = WTERMSIG(child_status); 158 | printf("!! signal (%d) %s\n", signum, strsignal(signum)); 159 | switch (signum) { 160 | case SIGABRT: 161 | status = test::SIGNAL_ABORT; 162 | break; 163 | case SIGSEGV: 164 | case SIGBUS: 165 | status = test::SIGNAL_SEGFAULT; 166 | break; 167 | case SIGFPE: 168 | status = test::SIGNAL_DIVZERO; 169 | break; 170 | default: 171 | status = test::SIGNAL_UNCAUGHT; 172 | } 173 | } 174 | 175 | #endif 176 | 177 | if (test.expected_status == test::FAILED) { 178 | return (status & test::FAILED); 179 | } 180 | 181 | if (test.expected_status == test::SIGNAL_UNCAUGHT) { 182 | return (status & test::SIGNAL_UNCAUGHT); 183 | } 184 | 185 | return status == test.expected_status; 186 | } 187 | 188 | int main(int argc, const char *const argv[]) { 189 | 190 | #ifdef _WIN32 191 | _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); 192 | #endif 193 | 194 | if (argc == 3 && strcmp("--nofork", argv[1]) == 0) { 195 | // Windows has no fork, so we simulate it 196 | // we only execute one test, without forking 197 | for (test_registry_t::iterator it = test_registry().begin(); 198 | it != test_registry().end(); ++it) { 199 | TestBase &test = **it; 200 | if (strcasecmp(argv[2], test.name) == 0) { 201 | run_test(test, false); 202 | 203 | return 0; 204 | } 205 | } 206 | return -1; 207 | } 208 | 209 | size_t success_cnt = 0; 210 | size_t total_cnt = 0; 211 | for (test_registry_t::iterator it = test_registry().begin(); 212 | it != test_registry().end(); ++it) { 213 | TestBase &test = **it; 214 | 215 | bool consider_test = (argc <= 1); 216 | for (int i = 1; i < argc; ++i) { 217 | if (strcasecmp(argv[i], test.name) == 0) { 218 | consider_test = true; 219 | break; 220 | } 221 | } 222 | if (!consider_test) { 223 | continue; 224 | } 225 | 226 | total_cnt += 1; 227 | if (run_test(test)) { 228 | printf("-- test case success: %s\n", test.name); 229 | success_cnt += 1; 230 | } else { 231 | printf("** test case FAILED : %s\n", test.name); 232 | } 233 | } 234 | printf("-- tests passing: %zu/%zu", success_cnt, total_cnt); 235 | if (total_cnt) { 236 | printf(" (%zu%%)\n", success_cnt * 100 / total_cnt); 237 | } else { 238 | printf("\n"); 239 | } 240 | return (success_cnt == total_cnt) ? EXIT_SUCCESS : EXIT_FAILURE; 241 | } 242 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test/rectrace.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test/rectrace.cpp 3 | * Copyright 2013 Google Inc. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "backward.hpp" 25 | #include "test/test.hpp" 26 | #include 27 | 28 | using namespace backward; 29 | 30 | typedef StackTrace stacktrace_t; 31 | 32 | void end_of_our_journey(stacktrace_t &st) { 33 | if (!st.size()) { 34 | st.load_here(); 35 | } 36 | } 37 | 38 | int rec(stacktrace_t &st, int level) { 39 | if (level <= 1) { 40 | end_of_our_journey(st); 41 | return 0; 42 | } 43 | return rec(st, level - 1); 44 | } 45 | 46 | namespace toto { 47 | 48 | namespace titi { 49 | 50 | struct foo { 51 | 52 | union bar { 53 | NOINLINE static int trampoline(stacktrace_t &st, int level) { 54 | return rec(st, level); 55 | } 56 | }; 57 | }; 58 | 59 | } // namespace titi 60 | 61 | } // namespace toto 62 | 63 | TEST(recursion) { 64 | { // lexical scope. 65 | stacktrace_t st; 66 | const int input = 3; 67 | int r = toto::titi::foo::bar::trampoline(st, input); 68 | 69 | std::cout << "rec(" << input << ") == " << r << std::endl; 70 | 71 | Printer printer; 72 | // printer.address = true; 73 | printer.object = true; 74 | printer.print(st, stdout); 75 | } 76 | } 77 | 78 | int fib(StackTrace &st, int level) { 79 | if (level == 2) { 80 | return 1; 81 | } 82 | if (level <= 1) { 83 | end_of_our_journey(st); 84 | return 0; 85 | } 86 | return fib(st, level - 1) + fib(st, level - 2); 87 | } 88 | 89 | TEST(fibrecursive) { 90 | StackTrace st; 91 | const int input = 6; 92 | int r = fib(st, input); 93 | 94 | std::cout << "fib(" << input << ") == " << r << std::endl; 95 | 96 | Printer printer; 97 | printer.print(st, stdout); 98 | } 99 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test/select_signals.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test/segfault.cpp 3 | * Copyright 2013 Google Inc. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "backward.hpp" 25 | 26 | #include "test/test.hpp" 27 | #include 28 | #include 29 | 30 | using namespace backward; 31 | 32 | void badass_function() { 33 | char *ptr = (char *)42; 34 | *ptr = 42; 35 | } 36 | 37 | TEST_SEGFAULT(pprint_sigsev) { 38 | std::vector signals; 39 | signals.push_back(SIGSEGV); 40 | SignalHandling sh(signals); 41 | std::cout << std::boolalpha << "sh.loaded() == " << sh.loaded() << std::endl; 42 | badass_function(); 43 | } 44 | 45 | TEST_SEGFAULT(wont_pprint) { 46 | std::vector signals; 47 | signals.push_back(SIGABRT); 48 | SignalHandling sh(signals); 49 | std::cout << std::boolalpha << "sh.loaded() == " << sh.loaded() << std::endl; 50 | badass_function(); 51 | } 52 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test/stacktrace.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test/stacktrace.cpp 3 | * Copyright 2013 Google Inc. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "backward.hpp" 25 | #include "test/test.hpp" 26 | #include 27 | #include 28 | 29 | using namespace backward; 30 | 31 | void collect_trace(StackTrace &st) { st.load_here(); } 32 | 33 | TEST(minitrace) { 34 | Printer printer; 35 | 36 | StackTrace st; 37 | collect_trace(st); 38 | 39 | printer.print(st, std::cout); 40 | } 41 | 42 | void d(StackTrace &st) { st.load_here(); } 43 | 44 | void c(StackTrace &st) { return d(st); } 45 | 46 | void b(StackTrace &st) { return c(st); } 47 | 48 | NOINLINE void a(StackTrace &st) { return b(st); } 49 | 50 | TEST(smalltrace) { 51 | Printer printer; 52 | 53 | StackTrace st; 54 | a(st); 55 | 56 | printer.print(st, std::cout); 57 | } 58 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test/suicide.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test/suicide.cpp 3 | * Copyright 2013 Google Inc. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "backward.hpp" 25 | 26 | #include "test/test.hpp" 27 | #include 28 | 29 | #ifndef _WIN32 30 | #include 31 | #endif 32 | 33 | using namespace backward; 34 | 35 | void badass_function() { 36 | char *ptr = (char *)42; 37 | *ptr = 42; 38 | } 39 | 40 | TEST_SEGFAULT(invalid_write) { badass_function(); } 41 | 42 | int you_shall_not_pass() { 43 | char *ptr = (char *)42; 44 | int v = *ptr; 45 | return v; 46 | } 47 | 48 | TEST_SEGFAULT(invalid_read) { 49 | int v = you_shall_not_pass(); 50 | std::cout << "v=" << v << std::endl; 51 | } 52 | 53 | void abort_abort_I_repeat_abort_abort() { 54 | std::cout << "Jumping off the boat!" << std::endl; 55 | abort(); 56 | } 57 | 58 | TEST_ABORT(calling_abort) { abort_abort_I_repeat_abort_abort(); } 59 | 60 | // aarch64 and mips does not trap Division by zero 61 | #if !defined(__aarch64__) || !defined(__mips__) 62 | volatile int zero = 0; 63 | 64 | int divide_by_zero() { 65 | std::cout << "And the wild black hole appears..." << std::endl; 66 | int v = 42 / zero; 67 | return v; 68 | } 69 | 70 | TEST_DIVZERO(divide_by_zero) { 71 | int v = divide_by_zero(); 72 | std::cout << "v=" << v << std::endl; 73 | } 74 | #endif 75 | 76 | // Darwin does not allow RLIMIT_STACK to be reduced 77 | #ifndef __APPLE__ 78 | int bye_bye_stack(int i) { return bye_bye_stack(i + 1) + bye_bye_stack(i * 2); } 79 | 80 | TEST_SEGFAULT(stackoverflow) { 81 | #ifndef _WIN32 82 | struct rlimit limit; 83 | limit.rlim_max = 8096; 84 | setrlimit(RLIMIT_STACK, &limit); 85 | #endif 86 | int r = bye_bye_stack(42); 87 | std::cout << "r=" << r << std::endl; 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test/test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test/test.cpp 3 | * Copyright 2013 Google Inc. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #include "test/test.hpp" 25 | #include 26 | #include 27 | #include 28 | 29 | TEST(empty_test) {} 30 | 31 | TEST_FAIL_ASSERT(fail_assert) { ASSERT(1 == 2); } 32 | 33 | TEST_FAIL_ASSERT(fail_assert_ge) { ASSERT_GE(4, 5); } 34 | 35 | TEST_UNCAUGHT_EXCEPTION(uncaught_exception) { 36 | throw std::runtime_error("some random runtime error"); 37 | } 38 | 39 | TEST_UNCAUGHT_EXCEPTION(uncaught_exception_int) { throw 42; } 40 | 41 | TEST_SEGFAULT(segfault) { 42 | char *a = 0; 43 | char b = a[42]; 44 | std::cout << "result: " << b << std::endl; 45 | } 46 | 47 | TEST_ABORT(abort) { abort(); } 48 | 49 | TEST(catch_int) { 50 | ASSERT_THROW({ throw 42; }, int); 51 | } 52 | 53 | TEST_FAIL_ASSERT(fail_catch_int) { ASSERT_THROW({}, int); } 54 | 55 | TEST_FAIL_ASSERT(fail_no_throw) { 56 | ASSERT_NO_THROW({ throw 42; }); 57 | } 58 | 59 | TEST(any_throw) { 60 | ASSERT_ANY_THROW({ throw 42; }); 61 | } 62 | 63 | TEST_FAIL_ASSERT(fail_any_throw) { ASSERT_ANY_THROW({}); } 64 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test/test.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test/test.hpp 3 | * Copyright 2013 Google Inc. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #pragma once 25 | #ifndef H_54E531F7_9154_454B_BEB9_257408429470 26 | #define H_54E531F7_9154_454B_BEB9_257408429470 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace test { 36 | 37 | struct AssertFailedError : std::exception { 38 | ~AssertFailedError() throw() {} 39 | 40 | AssertFailedError(const char *filename, int _line, const char *_errmsg) 41 | : basename(_basename(filename)), line(_line), errmsg(_errmsg) {} 42 | 43 | const char *what() const throw() { 44 | if (!_what.size()) { 45 | std::ostringstream ss; 46 | ss << "assertion failed (" << basename << ":" << line; 47 | ss << ") " << errmsg; 48 | _what = ss.str(); 49 | } 50 | return _what.c_str(); 51 | } 52 | 53 | const char *basename; 54 | int line; 55 | const char *errmsg; 56 | 57 | mutable std::string _what; 58 | 59 | static const char *_basename(const char *filename) { 60 | const char *basename = filename + strlen(filename); 61 | while (basename != filename && *basename != '/') { 62 | basename -= 1; 63 | } 64 | return basename + 1; 65 | } 66 | }; 67 | 68 | enum TestStatus { 69 | SUCCESS = 0 << 0, 70 | FAILED = 1 << 0, 71 | 72 | ASSERT_FAIL = FAILED | 1 << 1, 73 | EXCEPTION_UNCAUGHT = FAILED | 2 << 1, 74 | SIGNAL_UNCAUGHT = FAILED | 3 << 1, 75 | SIGNAL_SEGFAULT = SIGNAL_UNCAUGHT | 1 << 3, 76 | SIGNAL_ABORT = SIGNAL_UNCAUGHT | 2 << 3, 77 | SIGNAL_DIVZERO = SIGNAL_UNCAUGHT | 2 << 3, 78 | 79 | STATUS_MASK = 0x1F 80 | }; 81 | 82 | struct TestBase { 83 | const char *name; 84 | TestStatus expected_status; 85 | 86 | virtual ~TestBase() {} 87 | TestBase(const char *, TestStatus); 88 | virtual void do_test() = 0; 89 | 90 | TestStatus run() { 91 | try { 92 | do_test(); 93 | return SUCCESS; 94 | } catch (const AssertFailedError &e) { 95 | printf("!! %s\n", e.what()); 96 | return ASSERT_FAIL; 97 | } catch (const std::exception &e) { 98 | printf("!! exception: %s\n", e.what()); 99 | return EXCEPTION_UNCAUGHT; 100 | } catch (...) { 101 | printf("!! unknown exception\n"); 102 | return EXCEPTION_UNCAUGHT; 103 | } 104 | } 105 | }; 106 | 107 | typedef std::vector test_registry_t; 108 | inline test_registry_t &test_registry() { 109 | static test_registry_t reg; 110 | return reg; 111 | } 112 | 113 | inline TestBase::TestBase(const char *n, TestStatus s) 114 | : name(n), expected_status(s) { 115 | test_registry().push_back(this); 116 | } 117 | 118 | } // namespace test 119 | 120 | #define _TEST_STATUS(name, status) \ 121 | struct TEST_##name : ::test::TestBase { \ 122 | TEST_##name() : TestBase(#name, status) {} \ 123 | void do_test(); \ 124 | } TEST_##name; \ 125 | void TEST_##name::do_test() 126 | 127 | #define TEST(name) _TEST_STATUS(name, ::test::SUCCESS) 128 | #define TEST_FAIL(name) _TEST_STATUS(name, ::test::FAILED) 129 | #define TEST_FAIL_ASSERT(name) _TEST_STATUS(name, ::test::ASSERT_FAIL) 130 | #define TEST_UNCAUGHT_EXCEPTION(name) \ 131 | _TEST_STATUS(name, ::test::EXCEPTION_UNCAUGHT) 132 | #define TEST_UNCAUGHT_SIGNAL(name) _TEST_STATUS(name, ::test::SIGNAL_UNCAUGHT) 133 | #define TEST_SEGFAULT(name) _TEST_STATUS(name, ::test::SIGNAL_SEGFAULT) 134 | #define TEST_ABORT(name) _TEST_STATUS(name, ::test::SIGNAL_ABORT) 135 | #define TEST_DIVZERO(name) _TEST_STATUS(name, ::test::SIGNAL_DIVZERO) 136 | 137 | #define ASSERT(expr) \ 138 | (expr) ? static_cast(0) \ 139 | : throw ::test::AssertFailedError(__FILE__, __LINE__, #expr) 140 | 141 | #define _ASSERT_BINOP(a, b, cmp) \ 142 | (!(a cmp b)) ? static_cast(0) \ 143 | : throw ::test::AssertFailedError( \ 144 | __FILE__, __LINE__, "because " #a " " #cmp " " #b) 145 | 146 | #define ASSERT_EQ(a, b) _ASSERT_BINOP(a, b, !=) 147 | #define ASSERT_NE(a, b) _ASSERT_BINOP(a, b, ==) 148 | #define ASSERT_LT(a, b) _ASSERT_BINOP(a, b, >=) 149 | #define ASSERT_LE(a, b) _ASSERT_BINOP(a, b, >) 150 | #define ASSERT_GT(a, b) _ASSERT_BINOP(a, b, <=) 151 | #define ASSERT_GE(a, b) _ASSERT_BINOP(a, b, <) 152 | 153 | #define ASSERT_THROW(expr, e_type) \ 154 | do { \ 155 | try { \ 156 | expr \ 157 | } catch (const e_type &) { \ 158 | break; \ 159 | } \ 160 | throw ::test::AssertFailedError(__FILE__, __LINE__, \ 161 | "expected exception " #e_type); \ 162 | } while (0) 163 | 164 | #define ASSERT_ANY_THROW(expr) \ 165 | do { \ 166 | try { \ 167 | expr \ 168 | } catch (...) { \ 169 | break; \ 170 | } \ 171 | throw ::test::AssertFailedError(__FILE__, __LINE__, \ 172 | "expected any exception"); \ 173 | } while (0) 174 | 175 | #define ASSERT_NO_THROW(expr) \ 176 | try { \ 177 | expr \ 178 | } catch (...) { \ 179 | throw ::test::AssertFailedError(__FILE__, __LINE__, \ 180 | "no exception expected"); \ 181 | } 182 | 183 | #endif /* H_GUARD */ 184 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test_package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(backward-package-test) 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) 5 | conan_basic_setup(TARGETS) 6 | 7 | add_executable(example main.cpp) 8 | target_link_libraries(example PRIVATE ${CONAN_TARGETS}) 9 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test_package/conanfile.py: -------------------------------------------------------------------------------- 1 | from conans import ConanFile, CMake 2 | import os 3 | 4 | class TestBackward(ConanFile): 5 | settings = 'os', 'compiler', 'build_type', 'arch' 6 | generators = 'cmake' 7 | 8 | def build(self): 9 | cmake = CMake(self) 10 | cmake.configure(defs={'CMAKE_VERBOSE_MAKEFILE': 'ON'}) 11 | cmake.build() 12 | 13 | def test(self): 14 | self.run(os.path.join('.', 'bin', 'example')) 15 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/vendor/bombela/backward-cpp/test_package/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace backward; 7 | 8 | class TracedException : public std::runtime_error { 9 | public: 10 | TracedException() : std::runtime_error(_get_trace()) {} 11 | 12 | private: 13 | std::string _get_trace() { 14 | std::ostringstream ss; 15 | 16 | StackTrace stackTrace; 17 | TraceResolver resolver; 18 | stackTrace.load_here(); 19 | resolver.load_stacktrace(stackTrace); 20 | 21 | for (std::size_t i = 0; i < stackTrace.size(); ++i) { 22 | const ResolvedTrace trace = resolver.resolve(stackTrace[i]); 23 | 24 | ss << "#" << i << " at " << trace.object_function << "\n"; 25 | } 26 | 27 | return ss.str(); 28 | } 29 | }; 30 | 31 | void f(int i) { 32 | if (i >= 42) { 33 | throw TracedException(); 34 | } else { 35 | std::cout << "i=" << i << "\n"; 36 | f(i + 1); 37 | } 38 | } 39 | 40 | int main() { 41 | try { 42 | f(0); 43 | } catch (const TracedException &ex) { 44 | std::cout << ex.what(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/memory_tools/verbosity.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "./safe_fwrite.hpp" 21 | #include "osrf_testing_tools_cpp/memory_tools/verbosity.hpp" 22 | 23 | namespace osrf_testing_tools_cpp 24 | { 25 | namespace memory_tools 26 | { 27 | 28 | static 29 | VerbosityLevel 30 | get_verbosity_level_from_env() 31 | { 32 | #if !defined(_WIN32) 33 | const char * value = std::getenv("MEMORY_TOOLS_VERBOSITY"); 34 | size_t size_of_value = 0; 35 | if (value) { 36 | size_of_value = strnlen(value, 2); 37 | } 38 | #else 39 | char value[256]; 40 | size_t size_of_value; 41 | errno_t my_errno = getenv_s(&size_of_value, value, sizeof(value), "MEMORY_TOOLS_VERBOSITY"); 42 | if (0 != my_errno) { 43 | throw std::runtime_error("getenv_s() falied"); 44 | } 45 | #endif 46 | if (!value || size_of_value == 0) { 47 | return VerbosityLevel::quiet; 48 | } 49 | if (0 == std::strncmp("quiet", value, 5) || 0 == std::strncmp("QUIET", value, 5)) { 50 | return VerbosityLevel::quiet; 51 | } 52 | if (0 == std::strncmp("debug", value, 5) || 0 == std::strncmp("DEBUG", value, 5)) { 53 | return VerbosityLevel::debug; 54 | } 55 | if (0 == std::strncmp("trace", value, 5) || 0 == std::strncmp("TRACE", value, 5)) { 56 | return VerbosityLevel::trace; 57 | } 58 | SAFE_FWRITE(stderr, "[memory_tools][WARN] Given MEMORY_TOOLS_VERBOSITY="); 59 | SAFE_FWRITE(stderr, value); 60 | SAFE_FWRITE(stderr, " but that is not one of {quiet, debug, trace}, using quiet.\n"); 61 | return VerbosityLevel::quiet; 62 | } 63 | 64 | static std::atomic g_verbosity_level(get_verbosity_level_from_env()); 65 | 66 | VerbosityLevel 67 | get_verbosity_level() 68 | { 69 | return g_verbosity_level.load(); 70 | } 71 | 72 | VerbosityLevel 73 | set_verbosity_level(VerbosityLevel verbosity_level) 74 | { 75 | return g_verbosity_level.exchange(verbosity_level); 76 | } 77 | 78 | } // namespace memory_tools 79 | } // namespace osrf_testing_tools_cpp 80 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/test_runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test_runner main.cpp) 2 | 3 | install(TARGETS test_runner 4 | EXPORT test_runner 5 | DESTINATION lib/${PROJECT_NAME} 6 | ) 7 | 8 | install(EXPORT test_runner 9 | DESTINATION share/${PROJECT_NAME}/cmake 10 | NAMESPACE "${PROJECT_NAME}::" 11 | FILE "test_runnerExport.cmake" 12 | ) 13 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/test_runner/execute_process.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef TEST_RUNNER__EXECUTE_PROCESS_HPP_ 16 | #define TEST_RUNNER__EXECUTE_PROCESS_HPP_ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #if defined(_WIN32) 25 | #include 26 | #else 27 | #include 28 | #include 29 | #include 30 | #endif 31 | 32 | namespace test_runner 33 | { 34 | 35 | namespace impl 36 | { 37 | 38 | #if defined(_WIN32) 39 | int execute_process_win32(const std::vector & commands); 40 | #else 41 | int execute_process_unix(const std::vector & commands); 42 | #endif 43 | 44 | } // namespace impl 45 | 46 | /// Execute a process and return the return code when it exits. 47 | int 48 | execute_process(const std::vector & commands) 49 | { 50 | #if defined(_WIN32) 51 | return impl::execute_process_win32(commands); 52 | #else 53 | return impl::execute_process_unix(commands); 54 | #endif 55 | } 56 | 57 | #if defined(_WIN32) 58 | 59 | int impl::execute_process_win32(const std::vector & commands) 60 | { 61 | int exit_code = -1; 62 | 63 | std::string command_str = ""; 64 | for (auto command : commands) { 65 | command_str += command + " "; 66 | } 67 | if (commands.size()) { 68 | // remove trailing " " 69 | command_str = command_str.substr(0, command_str.size() - 1); 70 | } 71 | LPSTR lpstr_command = _strdup(command_str.c_str()); 72 | 73 | STARTUPINFO info = {sizeof(info)}; 74 | PROCESS_INFORMATION processInfo; 75 | if (CreateProcess( 76 | NULL, lpstr_command, 77 | NULL, NULL, TRUE, 0, NULL, NULL, 78 | &info, &processInfo)) 79 | { 80 | WaitForSingleObject(processInfo.hProcess, INFINITE); 81 | 82 | DWORD dw_exit_code; 83 | GetExitCodeProcess(processInfo.hProcess, &dw_exit_code); 84 | exit_code = dw_exit_code; 85 | 86 | CloseHandle(processInfo.hProcess); 87 | CloseHandle(processInfo.hThread); 88 | } 89 | 90 | free(lpstr_command); 91 | 92 | return exit_code; 93 | } 94 | 95 | #else 96 | 97 | int impl::execute_process_unix(const std::vector & commands) 98 | { 99 | int exit_code = 0; 100 | 101 | pid_t pid = fork(); 102 | if (-1 == pid) { 103 | throw std::runtime_error("failed to fork()"); 104 | } else if (0 == pid) { 105 | // child 106 | // executable to be run (found on PATH) 107 | const char * cmd = commands[0].data(); 108 | // argv for new process (need non-const char *'s), including program name in slot 0 109 | std::vector arguments; 110 | auto it = commands.cbegin(); 111 | for (; it != commands.cend(); ++it) { 112 | // dup strings to get non-const, free'd after execvp 113 | arguments.push_back(strdup(it->data())); 114 | } 115 | arguments.push_back(nullptr); // explicit nullptr to tell execvp where to stop 116 | int ret = execvp(cmd, arguments.data()); 117 | for (auto str : arguments) { 118 | free(str); 119 | str = nullptr; 120 | } 121 | if (-1 == ret) { 122 | fprintf(stderr, "failed to call execvp(): %s\n", strerror(errno)); 123 | } 124 | _exit(127); 125 | } else { 126 | // parent 127 | int status; 128 | if (waitpid(pid, &status, 0) == -1) { 129 | throw std::runtime_error("failed to waitpid()"); 130 | } else { 131 | if (WIFSIGNALED(status)) { 132 | exit_code = -WTERMSIG(status); 133 | } else if (WIFEXITED(status)) { 134 | exit_code = WEXITSTATUS(status); 135 | } else if (WIFSTOPPED(status)) { 136 | exit_code = -WSTOPSIG(status); 137 | } else { 138 | // should not happen 139 | throw std::runtime_error("unknown child exit status"); 140 | } 141 | } 142 | } 143 | 144 | return exit_code; 145 | } 146 | 147 | #endif 148 | 149 | } // namespace test_runner 150 | 151 | #endif // TEST_RUNNER__EXECUTE_PROCESS_HPP_ 152 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/test_runner/get_environment_variable.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef TEST_RUNNER__GET_ENVIRONMENT_VARIABLE_HPP_ 16 | #define TEST_RUNNER__GET_ENVIRONMENT_VARIABLE_HPP_ 17 | 18 | #include 19 | #include 20 | 21 | namespace test_runner 22 | { 23 | 24 | /// Return value for environment variable, or "" if not set. 25 | std::string 26 | get_environment_variable(const std::string & env_var_name) 27 | { 28 | const char * env_value = nullptr; 29 | #if defined(_WIN32) 30 | char * dup_env_value = nullptr; 31 | size_t dup_env_value_len = 0; 32 | errno_t ret = _dupenv_s(&dup_env_value, &dup_env_value_len, env_var_name.c_str()); 33 | if (ret) { 34 | throw std::runtime_error("failed to get environment variable"); 35 | } 36 | env_value = dup_env_value; 37 | #else 38 | env_value = std::getenv(env_var_name.c_str()); 39 | #endif 40 | if (!env_value) { 41 | env_value = ""; 42 | } 43 | std::string return_value = env_value; 44 | #if defined(_WIN32) 45 | // also done with env_value, so free dup_env_value 46 | free(dup_env_value); 47 | #endif 48 | return return_value; 49 | } 50 | 51 | } // namespace test_runner 52 | 53 | #endif // TEST_RUNNER__GET_ENVIRONMENT_VARIABLE_HPP_ 54 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/test_runner/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "./execute_process.hpp" 24 | #include "./get_environment_variable.hpp" 25 | #include "./starts_with.hpp" 26 | #include "./parse_environment_variable.hpp" 27 | 28 | void 29 | usage(const std::string & program_name) 30 | { 31 | printf( 32 | "usage: %s " 33 | "[--env ENV=VALUE [ENV2=VALUE [...]]] " 34 | "[--append-env ENV=VALUE [ENV2=VALUE [...]]] " 35 | "-- \n", program_name.c_str()); 36 | } 37 | 38 | int 39 | main(int argc, char const * argv[]) 40 | { 41 | std::vector args; 42 | args.reserve(static_cast(argc)); 43 | for (int i = 0; i < argc; ++i) { 44 | if (i == 0) { 45 | continue; 46 | } 47 | args.emplace_back(argv[i]); 48 | } 49 | 50 | bool should_show_usage_and_exit = (args.size() <= 1); 51 | for (auto arg : args) { 52 | should_show_usage_and_exit |= test_runner::starts_with_any(arg, {"-h", "--help"}); 53 | } 54 | if (should_show_usage_and_exit) { 55 | usage(argv[0]); 56 | return 1; 57 | } 58 | 59 | std::map env_variables; 60 | std::map append_env_variables; 61 | std::vector commands; 62 | 63 | std::string mode = "none"; 64 | for (auto arg : args) { 65 | if (arg.empty()) { 66 | fprintf(stderr, "argument unexpectedly empty: %s\n", arg.c_str()); 67 | return 1; 68 | } 69 | // once in command mode, consume all flags no matter the content 70 | if (mode == "command") { 71 | commands.push_back(arg); 72 | continue; 73 | } 74 | 75 | // determine if the mode needs to change 76 | if (test_runner::starts_with(arg, "--env")) { 77 | mode = "env"; 78 | continue; 79 | } 80 | if (test_runner::starts_with(arg, "--append-env")) { 81 | mode = "append_env"; 82 | continue; 83 | } 84 | if (arg == "--") { 85 | mode = "command"; 86 | continue; 87 | } 88 | 89 | // determine where to store the argument 90 | if (mode == "none") { 91 | fprintf(stderr, "unexpected positional argument: %s\n", arg.c_str()); 92 | usage(argv[0]); 93 | return 1; 94 | } else if (mode == "env") { 95 | try { 96 | auto env_pair = test_runner::parse_environment_variable(arg); 97 | env_variables[env_pair.first] = env_pair.second; 98 | } catch (const std::invalid_argument & exc) { 99 | fprintf( 100 | stderr, 101 | "invalid environment variable, expected ENV=VALUE, %s: %s\n", 102 | exc.what(), arg.c_str()); 103 | return 1; 104 | } 105 | } else if (mode == "append_env") { 106 | try { 107 | auto env_pair = test_runner::parse_environment_variable(arg); 108 | append_env_variables[env_pair.first] = env_pair.second; 109 | } catch (const std::invalid_argument & exc) { 110 | fprintf( 111 | stderr, 112 | "invalid environment variable, expected ENV=VALUE, %s: %s\n", 113 | exc.what(), arg.c_str()); 114 | return 1; 115 | } 116 | } else { 117 | fprintf(stderr, "unexpected mode '%s'\n", mode.c_str()); 118 | return 1; 119 | } 120 | } 121 | 122 | // Set the environment variables. 123 | for (auto pair : env_variables) { 124 | #if defined(_WIN32) 125 | if (0 != _putenv_s(pair.first.c_str(), pair.second.c_str())) { 126 | #else 127 | if (0 != setenv(pair.first.c_str(), pair.second.c_str(), 1)) { 128 | #endif 129 | fprintf(stderr, 130 | "failed to set environment variable '%s=%s'\n", 131 | pair.first.c_str(), pair.second.c_str()); 132 | return 1; 133 | } 134 | } 135 | 136 | // Append the PATH-like environment variables. 137 | for (auto pair : append_env_variables) { 138 | std::string new_value; 139 | try { 140 | new_value = test_runner::get_environment_variable(pair.first.c_str()); 141 | } catch (const std::runtime_error &) { 142 | fprintf(stderr, "failed to get environment variable '%s'\n", pair.first.c_str()); 143 | return 1; 144 | } 145 | #if defined(_WIN32) 146 | auto path_sep = ";"; 147 | #else 148 | auto path_sep = ":"; 149 | #endif 150 | if (!new_value.empty() && new_value.substr(new_value.size() - 1) != path_sep) { 151 | new_value += path_sep; 152 | } 153 | new_value += pair.second; 154 | #if defined(_WIN32) 155 | if (0 != _putenv_s(pair.first.c_str(), new_value.c_str())) { 156 | #else 157 | if (0 != setenv(pair.first.c_str(), new_value.c_str(), 1)) { 158 | #endif 159 | fprintf(stderr, 160 | "failed to set environment variable '%s=%s'\n", 161 | pair.first.c_str(), new_value.c_str()); 162 | return 1; 163 | } 164 | } 165 | 166 | // Run the command. 167 | return test_runner::execute_process(commands); 168 | } 169 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/test_runner/parse_environment_variable.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef TEST_RUNNER__PARSE_ENVIRONMENT_VARIABLE_HPP_ 16 | #define TEST_RUNNER__PARSE_ENVIRONMENT_VARIABLE_HPP_ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace test_runner 24 | { 25 | 26 | std::pair 27 | parse_environment_variable(const std::string & argument) 28 | { 29 | if (argument.empty()) { 30 | throw std::invalid_argument("argument is empty"); 31 | } 32 | if (argument.size() < 3) { 33 | // need at least `k=v` 34 | throw std::invalid_argument("argument is not long enough"); 35 | } 36 | auto first_equal_sign = argument.find_first_of('='); 37 | if (first_equal_sign == 0) { 38 | throw std::invalid_argument("argument starts with a '='"); 39 | } 40 | if (first_equal_sign == std::string::npos) { 41 | throw std::invalid_argument("argument does not contain '='"); 42 | } 43 | return {argument.substr(0, first_equal_sign), argument.substr(first_equal_sign + 1)}; 44 | } 45 | 46 | } // namespace test_runner 47 | 48 | #endif // TEST_RUNNER__PARSE_ENVIRONMENT_VARIABLE_HPP_ 49 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/src/test_runner/starts_with.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef TEST_RUNNER__STARTS_WITH_HPP_ 16 | #define TEST_RUNNER__STARTS_WITH_HPP_ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | namespace test_runner 23 | { 24 | 25 | /// Return true if a string starts with a prefix. 26 | bool 27 | starts_with(const std::string & str, const std::string & prefix) 28 | { 29 | return !str.compare(0, prefix.size(), prefix); 30 | } 31 | 32 | /// Return true if a string starts with any of the given prefixes. 33 | bool 34 | starts_with_any(const std::string & str, const std::vector & prefixes) 35 | { 36 | for (auto prefix : prefixes) { 37 | if (test_runner::starts_with(str, prefix)) { 38 | return true; 39 | } 40 | } 41 | return false; 42 | } 43 | 44 | } // namespace test_runner 45 | 46 | #endif // TEST_RUNNER__STARTS_WITH_HPP_ 47 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(cmake) 2 | add_subdirectory(memory_tools) 3 | add_subdirectory(test_runner) 4 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/test/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Test logic for version filtering when selecting googletest version. 2 | add_test( 3 | NAME "test_osrf_testing_tools_cpp_filter_versions_cmake" 4 | COMMAND 5 | ${CMAKE_COMMAND} -P 6 | "${CMAKE_SOURCE_DIR}/test/cmake/test_osrf_testing_tools_cpp_filter_versions.cmake" 7 | ) -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/test/cmake/test_osrf_testing_tools_cpp_filter_versions.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | include(${CMAKE_CURRENT_LIST_DIR}/../../cmake/osrf_testing_tools_cpp_require_googletest.cmake) 16 | 17 | set(versions) 18 | 19 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_EQ 1.8) 20 | if(valid_versions) 21 | message(FATAL_ERROR "expected valid versions to be empty, got '${valid_versions}'") 22 | endif() 23 | 24 | set(versions 1.7.0;1.8.0) 25 | 26 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_EQ 1.9) 27 | if(valid_versions) 28 | message(FATAL_ERROR "expected valid versions to be empty, got '${valid_versions}'") 29 | endif() 30 | 31 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_EQ 1.8.1) 32 | if(valid_versions) 33 | message(FATAL_ERROR "expected valid versions to be empty, got '${valid_versions}'") 34 | endif() 35 | 36 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_EQ 1.8) 37 | if(NOT valid_versions EQUAL 1) 38 | message(FATAL_ERROR "expected valid version index of 1, got '${valid_versions}'") 39 | endif() 40 | 41 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_EQ 1.8.0) 42 | if(NOT valid_versions EQUAL 1) 43 | message(FATAL_ERROR "expected valid version index of 1, got '${valid_versions}'") 44 | endif() 45 | 46 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_LT 1.7) 47 | if(valid_versions) 48 | message(FATAL_ERROR "expected valid versions to be empty, got '${valid_versions}'") 49 | endif() 50 | 51 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_LT 1.8) 52 | if(NOT valid_versions EQUAL 0) 53 | message(FATAL_ERROR "expected valid version index of 0, got '${valid_versions}'") 54 | endif() 55 | 56 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_LT 1.9) 57 | if(NOT valid_versions EQUAL "0;1") 58 | message(FATAL_ERROR "expected valid version indexes of 0 and 1, got '${valid_versions}'") 59 | endif() 60 | 61 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_LTE 1.7) 62 | if(NOT valid_versions EQUAL 0) 63 | message(FATAL_ERROR "expected valid versions to be 0, got '${valid_versions}'") 64 | endif() 65 | 66 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_LTE 1.8) 67 | if(NOT valid_versions EQUAL "0;1") 68 | message(FATAL_ERROR "expected valid version indexes of 0 and 1, got '${valid_versions}'") 69 | endif() 70 | 71 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_LTE 1.6) 72 | if(valid_versions) 73 | message(FATAL_ERROR "expected valid versions to be empty, got '${valid_versions}'") 74 | endif() 75 | 76 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_GT 1.8) 77 | if(valid_versions) 78 | message(FATAL_ERROR "expected valid versions to be empty, got '${valid_versions}'") 79 | endif() 80 | 81 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_GT 1.7) 82 | if(NOT valid_versions EQUAL 1) 83 | message(FATAL_ERROR "expected valid version index of 1, got '${valid_versions}'") 84 | endif() 85 | 86 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_GT 1.6) 87 | if(NOT valid_versions EQUAL "0;1") 88 | message(FATAL_ERROR "expected valid version indexes of 0 and 1, got '${valid_versions}'") 89 | endif() 90 | 91 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_GTE 1.8) 92 | if(NOT valid_versions EQUAL 1) 93 | message(FATAL_ERROR "expected valid versions to be 1, got '${valid_versions}'") 94 | endif() 95 | 96 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_GTE 1.7) 97 | if(NOT valid_versions EQUAL "0;1") 98 | message(FATAL_ERROR "expected valid version indexes of 0 and 1, got '${valid_versions}'") 99 | endif() 100 | 101 | _osrf_testing_tools_cpp_filter_versions(valid_versions versions VERSION_GTE 1.9) 102 | if(valid_versions) 103 | message(FATAL_ERROR "expected valid versions to be empty, got '${valid_versions}'") 104 | endif() 105 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/test/memory_tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Create tests for the memory tools library. 2 | add_executable(test_memory_tools test_memory_tools.cpp) 3 | target_link_libraries(test_memory_tools 4 | memory_tools 5 | gtest_main 6 | ) 7 | target_include_directories(test_memory_tools 8 | PRIVATE ${memory_tools_src_dir_internal_testing_only}) 9 | 10 | if(memory_tools_is_available) 11 | add_test( 12 | NAME "test_memory_tools" 13 | COMMAND 14 | "$" 15 | --env 16 | ${memory_tools_extra_test_env} 17 | -- 18 | "$" 19 | ) 20 | endif() 21 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/test/test_runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Test parsing of environment variables 2 | add_executable(test_parse_environment_variable test_parse_environment_variable.cpp) 3 | # gtest_main is found by osrf_testing_tools_cpp_require_googletest(), called in main CMakeLists.txt 4 | target_link_libraries(test_parse_environment_variable gtest_main) 5 | add_test( 6 | NAME "test_parse_environment_variable" 7 | COMMAND "$" 8 | ) 9 | 10 | # Test the test_runner's ability to influence environment variables in tests 11 | add_executable(assert_env_vars assert_env_vars.cpp) 12 | # gtest_main is found by osrf_testing_tools_cpp_require_googletest(), called in main CMakeLists.txt 13 | target_link_libraries(assert_env_vars gtest_main) 14 | 15 | # The use of `:` in path-like env var's is converted to `;` by `assert_env_vars`. 16 | add_test( 17 | NAME "test_test_runner" 18 | COMMAND 19 | "$" 20 | --env 21 | FOO=bar 22 | PING=pong 23 | --append-env 24 | FOO=baz 25 | -- 26 | "$" 27 | --env 28 | FOO=bar:baz 29 | PING=pong 30 | ) 31 | 32 | # # This test can be uncommented to make sure a bad return code is propogated by test_runner. 33 | # add_test( 34 | # NAME "test_test_runner_fails" 35 | # COMMAND 36 | # "$" 37 | # --env 38 | # FOO=bar 39 | # PING=pong 40 | # --append-env 41 | # FOO=baz 42 | # -- 43 | # python3 -c "import sys; print('exiting with code 1'); sys.exit(1)" 44 | # ) 45 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/test/test_runner/assert_env_vars.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include // NOLINT(build/include_order) 25 | 26 | #include "../../src/test_runner/get_environment_variable.hpp" 27 | #include "../../src/test_runner/parse_environment_variable.hpp" 28 | #include "../../src/test_runner/starts_with.hpp" 29 | 30 | void 31 | usage(const std::string & program_name) 32 | { 33 | printf("usage: %s [--env ENV=VALUE [ENV2=VALUE [...]]]\n", program_name.c_str()); 34 | } 35 | 36 | std::vector g_args; 37 | 38 | TEST(TestTestRunner, environment_variables_set_correctly) 39 | { 40 | bool should_show_usage_and_exit = (g_args.size() <= 1); 41 | for (auto arg : g_args) { 42 | should_show_usage_and_exit |= test_runner::starts_with_any(arg, {"-h", "--help"}); 43 | } 44 | if (should_show_usage_and_exit) { 45 | usage(g_args[0].c_str()); 46 | FAIL(); 47 | } 48 | 49 | std::map env_variables; 50 | 51 | std::string mode = "none"; 52 | for (auto arg : g_args) { 53 | if (arg.empty()) { 54 | fprintf(stderr, "argument unexpectedly empty: %s\n", arg.c_str()); 55 | FAIL(); 56 | } 57 | // once in env mode, consume all flags no matter the content 58 | if (mode == "env") { 59 | auto env_pair = test_runner::parse_environment_variable(arg); 60 | env_variables[env_pair.first] = env_pair.second; 61 | continue; 62 | } 63 | 64 | // determine if the mode needs to change 65 | if (test_runner::starts_with(arg, "--env")) { 66 | mode = "env"; 67 | continue; 68 | } 69 | 70 | // determine where to store the argument 71 | if (mode == "none") { 72 | fprintf(stderr, "unexpected positional argument: %s\n", arg.c_str()); 73 | usage(g_args[0].c_str()); 74 | FAIL(); 75 | } 76 | } 77 | 78 | // Get the environment variables and check their values. 79 | for (auto pair : env_variables) { 80 | std::string expected_value = pair.second; 81 | #if defined(_WIN32) 82 | // replace `:` with `;` on Windows for path like env variables 83 | std::replace(expected_value.begin(), expected_value.end(), ':', ';'); 84 | #endif 85 | std::string actual_value = test_runner::get_environment_variable(pair.first.c_str()); 86 | EXPECT_EQ(expected_value, actual_value); 87 | } 88 | } 89 | 90 | int main(int argc, char * argv[]) 91 | { 92 | ::testing::InitGoogleTest(&argc, argv); 93 | 94 | g_args.reserve(static_cast(argc)); 95 | for (int i = 0; i < argc; ++i) { 96 | if (i == 0) { 97 | continue; 98 | } 99 | printf("%s\n", argv[i]); 100 | g_args.emplace_back(argv[i]); 101 | } 102 | 103 | return RUN_ALL_TESTS(); 104 | } 105 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/test/test_runner/test_parse_environment_variable.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | 18 | #include // NOLINT(build/include_order) 19 | 20 | #include "../../src/test_runner/parse_environment_variable.hpp" 21 | 22 | TEST(TestTestRunner, test_parse_environment_variable) { 23 | { 24 | std::string argument = ""; 25 | EXPECT_THROW(test_runner::parse_environment_variable(argument), std::invalid_argument); 26 | } 27 | { 28 | std::string argument = "12"; 29 | EXPECT_THROW(test_runner::parse_environment_variable(argument), std::invalid_argument); 30 | } 31 | { 32 | std::string argument = "longer"; 33 | EXPECT_THROW(test_runner::parse_environment_variable(argument), std::invalid_argument); 34 | } 35 | { 36 | std::string argument = "=bar"; 37 | EXPECT_THROW(test_runner::parse_environment_variable(argument), std::invalid_argument); 38 | } 39 | { 40 | std::string argument = "foo="; 41 | auto pair = test_runner::parse_environment_variable(argument); 42 | EXPECT_EQ("foo", pair.first); 43 | EXPECT_EQ("", pair.second); 44 | } 45 | { 46 | std::string argument = "foo=bar"; 47 | auto pair = test_runner::parse_environment_variable(argument); 48 | EXPECT_EQ("foo", pair.first); 49 | EXPECT_EQ("bar", pair.second); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/vendor/google/googletest/googletest-external-project-add.cmake.in: -------------------------------------------------------------------------------- 1 | # Based on recommendation on how to integrate googletest into a CMake project: 2 | # https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project 3 | 4 | cmake_minimum_required(VERSION 3.5) 5 | 6 | project(googletest-download NONE) 7 | 8 | # Avoid DOWNLOAD_EXTRACT_TIMESTAMP warning for CMake >= 3.24 9 | if (POLICY CMP0135) 10 | cmake_policy(SET CMP0135 NEW) 11 | endif() 12 | 13 | include(ExternalProject) 14 | ExternalProject_Add(googletest 15 | URL "@GOOGLETEST_ARCHIVE_LOCATION@" 16 | URL_MD5 "@GOOGLETEST_MD5SUM@" 17 | SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-@GOOGLETEST_VERSION@-src" 18 | BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-@GOOGLETEST_VERSION@-build" 19 | CONFIGURE_COMMAND "" 20 | BUILD_COMMAND "" 21 | INSTALL_COMMAND "" 22 | TEST_COMMAND "" 23 | LOG_DOWNLOAD OFF 24 | LOG_UPDATE OFF 25 | LOG_CONFIGURE OFF 26 | LOG_BUILD OFF 27 | LOG_TEST OFF 28 | LOG_INSTALL OFF 29 | ) 30 | -------------------------------------------------------------------------------- /osrf_testing_tools_cpp/vendor/google/googletest/release-1.14.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrf/osrf_testing_tools_cpp/748de1c14a5175e7727973761d53941adf26311c/osrf_testing_tools_cpp/vendor/google/googletest/release-1.14.0.tar.gz -------------------------------------------------------------------------------- /test_osrf_testing_tools_cpp/CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | Changelog for package test_osrf_testing_tools_cpp 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4 | 5 | 2.3.0 (2025-04-24) 6 | ------------------ 7 | 8 | 2.2.0 (2024-06-17) 9 | ------------------ 10 | * Update CMakeLists.txt (`#85 `_) 11 | * Contributors: mosfet80 12 | 13 | 2.1.0 (2024-04-26) 14 | ------------------ 15 | 16 | 2.0.0 (2024-02-07) 17 | ------------------ 18 | 19 | 1.7.0 (2023-04-28) 20 | ------------------ 21 | 22 | 1.5.3 (2023-04-11) 23 | ------------------ 24 | * Changing C++ Compile Version (`#76 `_) 25 | * Update maintainers (`#74 `_) 26 | * Contributors: Audrow Nash, Lucas Wendland 27 | 28 | 1.5.2 (2022-11-07) 29 | ------------------ 30 | 31 | 1.5.1 (2022-02-14) 32 | ------------------ 33 | 34 | 1.5.0 (2022-01-14) 35 | ------------------ 36 | * remove explicit use of -Werror (`#67 `_) 37 | * Contributors: William Woodall 38 | 39 | 1.4.0 (2020-12-08) 40 | ------------------ 41 | 42 | 1.3.2 (2020-05-21) 43 | ------------------ 44 | -------------------------------------------------------------------------------- /test_osrf_testing_tools_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(test_osrf_testing_tools_cpp) 4 | 5 | # Default to C++17 6 | if(NOT CMAKE_CXX_STANDARD) 7 | set(CMAKE_CXX_STANDARD 17) 8 | endif() 9 | 10 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 11 | add_compile_options(-Wall -Wextra -Wpedantic) 12 | endif() 13 | 14 | include(CTest) 15 | if(BUILD_TESTING) 16 | find_package(osrf_testing_tools_cpp REQUIRED) 17 | osrf_testing_tools_cpp_require_googletest(VERSION_GTE 1.14) # ensures target gtest_main exists 18 | get_target_property(memory_tools_available 19 | osrf_testing_tools_cpp::memory_tools LIBRARY_PRELOAD_ENVIRONMENT_IS_AVAILABLE) 20 | 21 | if(memory_tools_available) 22 | add_executable(test_example_memory_tools_gtest test/test_example_memory_tools.cpp) 23 | target_link_libraries(test_example_memory_tools_gtest 24 | gtest_main 25 | osrf_testing_tools_cpp::memory_tools 26 | ) 27 | get_target_property(extra_env_vars 28 | osrf_testing_tools_cpp::memory_tools LIBRARY_PRELOAD_ENVIRONMENT_VARIABLE) 29 | osrf_testing_tools_cpp_add_test(test_example_memory_tools 30 | COMMAND "$" 31 | ENV ${extra_env_vars} 32 | ) 33 | 34 | add_executable(test_is_not_working_gtest test/test_is_not_working.cpp) 35 | target_link_libraries(test_is_not_working_gtest 36 | gtest_main 37 | osrf_testing_tools_cpp::memory_tools 38 | ) 39 | osrf_testing_tools_cpp_add_test(test_is_not_working_gtest 40 | COMMAND "$" 41 | ) 42 | endif() 43 | endif() 44 | -------------------------------------------------------------------------------- /test_osrf_testing_tools_cpp/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | test_osrf_testing_tools_cpp 7 | 2.3.0 8 | Test package, which uses things exported by osrf_testing_tools_cpp. 9 | 10 | Geoffrey Biggs 11 | 12 | Apache License 2.0 13 | 14 | William Woodall 15 | 16 | cmake 17 | 18 | osrf_testing_tools_cpp 19 | 20 | 21 | cmake 22 | 23 | 24 | -------------------------------------------------------------------------------- /test_osrf_testing_tools_cpp/test/test_example_memory_tools.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "osrf_testing_tools_cpp/memory_tools/testing_helpers.hpp" 21 | #include "osrf_testing_tools_cpp/memory_tools/memory_tools.hpp" 22 | #include "osrf_testing_tools_cpp/scope_exit.hpp" 23 | 24 | void my_first_function(const std::string & str) 25 | { 26 | osrf_testing_tools_cpp::memory_tools::guaranteed_malloc(str); 27 | } 28 | 29 | int my_second_function(int a, int b) 30 | { 31 | return a + b; 32 | } 33 | 34 | TEST(TestMemoryTools, test_example) { 35 | // See the comment in my_first_function() for why we need this. 36 | const std::string dummy("hello"); 37 | 38 | // you must initialize memory tools, but uninitialization is optional 39 | osrf_testing_tools_cpp::memory_tools::initialize(); 40 | OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ 41 | osrf_testing_tools_cpp::memory_tools::uninitialize(); 42 | }); 43 | 44 | // create a callback for "unexpected" mallocs that does a non-fatal gtest 45 | // failure and then register it with memory tools 46 | auto on_unexpected_malloc = 47 | [](osrf_testing_tools_cpp::memory_tools::MemoryToolsService & service) { 48 | ADD_FAILURE() << "unexpected malloc"; 49 | // this will cause a bracktrace to be printed for each unexpected malloc 50 | service.print_backtrace(); 51 | }; 52 | osrf_testing_tools_cpp::memory_tools::on_unexpected_malloc(on_unexpected_malloc); 53 | 54 | // at this point, you'll still not get callbacks, since monitoring is not enabled 55 | // so calling either user function should not fail 56 | my_first_function(dummy); 57 | EXPECT_EQ(my_second_function(1, 2), 3); 58 | 59 | // enabling monitoring will allow checking to begin, but the default state is 60 | // that dynamic memory calls are expected, so again either function will pass 61 | osrf_testing_tools_cpp::memory_tools::enable_monitoring(); 62 | ASSERT_TRUE(osrf_testing_tools_cpp::memory_tools::is_working()); 63 | my_first_function(dummy); 64 | EXPECT_EQ(my_second_function(1, 2), 3); 65 | 66 | // if you then tell memory tools that malloc is unexpected, then it will call 67 | // your above callback, at least until you indicate malloc is expected again 68 | EXPECT_NONFATAL_FAILURE({ 69 | EXPECT_NO_MALLOC({ 70 | my_first_function(dummy); 71 | }); 72 | }, "unexpected malloc"); 73 | // There are also explicit begin/end functions if you need variables to leave the scope 74 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_begin(); 75 | int result = my_second_function(1, 2); 76 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_end(); 77 | EXPECT_EQ(result, 3); 78 | 79 | // enable monitoring only works in the current thread, but you can enable it for all threads 80 | osrf_testing_tools_cpp::memory_tools::enable_monitoring_in_all_threads(); 81 | std::thread t1([&dummy]() { 82 | EXPECT_NONFATAL_FAILURE({ 83 | EXPECT_NO_MALLOC({ 84 | my_first_function(dummy); 85 | }); 86 | }, "unexpected malloc"); 87 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_begin(); 88 | int result = my_second_function(1, 2); 89 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_end(); 90 | EXPECT_EQ(result, 3); 91 | }); 92 | t1.join(); 93 | 94 | // disabling monitoring in all threads should not catch the malloc in my_first_function() 95 | osrf_testing_tools_cpp::memory_tools::disable_monitoring_in_all_threads(); 96 | osrf_testing_tools_cpp::memory_tools::enable_monitoring(); 97 | std::thread t2([&dummy]() { 98 | EXPECT_NO_MALLOC({ 99 | my_first_function(dummy); 100 | }); 101 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_begin(); 102 | int result = my_second_function(1, 2); 103 | osrf_testing_tools_cpp::memory_tools::expect_no_malloc_end(); 104 | EXPECT_EQ(result, 3); 105 | }); 106 | t2.join(); 107 | } 108 | -------------------------------------------------------------------------------- /test_osrf_testing_tools_cpp/test/test_is_not_working.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Open Source Robotics Foundation, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | 18 | #include "osrf_testing_tools_cpp/memory_tools/memory_tools.hpp" 19 | #include "osrf_testing_tools_cpp/scope_exit.hpp" 20 | 21 | TEST(TestMemoryTools, test_is_not_working) { 22 | 23 | // you must initialize memory tools, but uninitialization is optional 24 | osrf_testing_tools_cpp::memory_tools::initialize(); 25 | OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ 26 | osrf_testing_tools_cpp::memory_tools::uninitialize(); 27 | }); 28 | 29 | osrf_testing_tools_cpp::memory_tools::enable_monitoring(); 30 | 31 | ASSERT_FALSE(osrf_testing_tools_cpp::memory_tools::is_working()); 32 | } 33 | --------------------------------------------------------------------------------