From 2497716f285b7377545ab6f7a834abe5bd927c94 Mon Sep 17 00:00:00 2001 From: William Woodall Date: Fri, 12 Oct 2018 11:50:29 -0700 Subject: [PATCH 1/3] add getters for callbacks --- .../memory_tools/register_hooks.hpp | 20 ++++++++++ .../src/memory_tools/register_hooks.cpp | 40 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/register_hooks.hpp b/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/register_hooks.hpp index 69c7a3d..58a1c36 100644 --- a/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/register_hooks.hpp +++ b/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/register_hooks.hpp @@ -50,6 +50,11 @@ OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void on_malloc(AnyMemoryToolsCallback callback); +/// Get the current on_malloc callback if set, otherwise null. +OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC +AnyMemoryToolsCallback +get_on_malloc(); + /// Call the registered callback for malloc. OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void @@ -65,6 +70,11 @@ OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void on_realloc(AnyMemoryToolsCallback callback); +/// Get the current on_realloc callback if set, otherwise null. +OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC +AnyMemoryToolsCallback +get_on_realloc(); + /// Call the registered callback for realloc. OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void @@ -80,6 +90,11 @@ OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void on_calloc(AnyMemoryToolsCallback callback); +/// Get the current on_calloc callback if set, otherwise null. +OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC +AnyMemoryToolsCallback +get_on_calloc(); + /// Call the registered callback for calloc. OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void @@ -95,6 +110,11 @@ OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void on_free(AnyMemoryToolsCallback callback); +/// Get the current on_free callback if set, otherwise null. +OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC +AnyMemoryToolsCallback +get_on_free(); + /// Call the registered callback for free. OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void diff --git a/osrf_testing_tools_cpp/src/memory_tools/register_hooks.cpp b/osrf_testing_tools_cpp/src/memory_tools/register_hooks.cpp index f790758..458516e 100644 --- a/osrf_testing_tools_cpp/src/memory_tools/register_hooks.cpp +++ b/osrf_testing_tools_cpp/src/memory_tools/register_hooks.cpp @@ -38,6 +38,16 @@ on_malloc(AnyMemoryToolsCallback callback) } } +AnyMemoryToolsCallback +get_on_malloc() +{ + auto current = g_on_malloc_callback.load(); + if (current) { + return *current; + } + return nullptr; +} + void dispatch_malloc(MemoryToolsService & service) { @@ -53,6 +63,16 @@ on_realloc(AnyMemoryToolsCallback callback) delete g_on_realloc_callback.exchange(new AnyMemoryToolsCallback(callback)); } +AnyMemoryToolsCallback +get_on_realloc() +{ + auto current = g_on_realloc_callback.load(); + if (current) { + return *current; + } + return nullptr; +} + void dispatch_realloc(MemoryToolsService & service) { @@ -68,6 +88,16 @@ on_calloc(AnyMemoryToolsCallback callback) delete g_on_calloc_callback.exchange(new AnyMemoryToolsCallback(callback)); } +AnyMemoryToolsCallback +get_on_calloc() +{ + auto current = g_on_calloc_callback.load(); + if (current) { + return *current; + } + return nullptr; +} + void dispatch_calloc(MemoryToolsService & service) { @@ -83,6 +113,16 @@ on_free(AnyMemoryToolsCallback callback) delete g_on_free_callback.exchange(new AnyMemoryToolsCallback(callback)); } +AnyMemoryToolsCallback +get_on_free() +{ + auto current = g_on_free_callback.load(); + if (current) { + return *current; + } + return nullptr; +} + void dispatch_free(MemoryToolsService & service) { From 0f55c1592c329b96ea40282d9f55dad48f8d515e Mon Sep 17 00:00:00 2001 From: William Woodall Date: Fri, 12 Oct 2018 11:52:02 -0700 Subject: [PATCH 2/3] add is_working check and test it --- .../memory_tools/is_working.hpp | 47 ++++++++++++++++ .../memory_tools/memory_tools.hpp | 1 + .../src/memory_tools/CMakeLists.txt | 1 + .../src/memory_tools/is_working.cpp | 55 +++++++++++++++++++ test_osrf_testing_tools_cpp/CMakeLists.txt | 9 +++ .../test/test_example_memory_tools.cpp | 14 +---- .../test/test_is_not_working.cpp | 32 +++++++++++ 7 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp create mode 100644 osrf_testing_tools_cpp/src/memory_tools/is_working.cpp create mode 100644 test_osrf_testing_tools_cpp/test/test_is_not_working.cpp diff --git a/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp b/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp new file mode 100644 index 0000000..ccc80da --- /dev/null +++ b/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp @@ -0,0 +1,47 @@ +// Copyright 2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__IS_WORKING_HPP_ +#define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__IS_WORKING_HPP_ + +#include + +#include "./visibility_control.hpp" + +namespace osrf_testing_tools_cpp +{ +namespace memory_tools +{ + +/// Return true if memory tools is enabled, installed (LD_PRELOAD was done), and working. +/** + * This works by temporarily installing a on_malloc hook and then calling + * malloc in a way that cannot be optimized out by the compiler. + */ +OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC +bool +is_working(); + +/// Copy an input string into allocated memory, guaranteeing malloc is called. +/** + * Makes sure that the compiler doesn't optimize the malloc and free out. + * Input string contents doesn't matter, but should be non-empty. + */ +void +guaranteed_malloc(const std::string & str); + +} // namespace memory_tools +} // namespace osrf_testing_tools_cpp + +#endif // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__IS_WORKING_HPP_ diff --git a/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/memory_tools.hpp b/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/memory_tools.hpp index 5b47e6c..26f10bb 100644 --- a/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/memory_tools.hpp +++ b/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/memory_tools.hpp @@ -20,6 +20,7 @@ #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__MEMORY_TOOLS_HPP_ #include "./initialize.hpp" +#include "./is_working.hpp" #include "./memory_tools_service.hpp" #include "./monitoring.hpp" #include "./register_hooks.hpp" diff --git a/osrf_testing_tools_cpp/src/memory_tools/CMakeLists.txt b/osrf_testing_tools_cpp/src/memory_tools/CMakeLists.txt index c5f2662..08b4d2f 100644 --- a/osrf_testing_tools_cpp/src/memory_tools/CMakeLists.txt +++ b/osrf_testing_tools_cpp/src/memory_tools/CMakeLists.txt @@ -2,6 +2,7 @@ add_library(memory_tools SHARED custom_memory_functions.cpp implementation_monitoring_override.cpp initialize.cpp + is_working.cpp memory_tools_service.cpp monitoring.cpp register_hooks.cpp diff --git a/osrf_testing_tools_cpp/src/memory_tools/is_working.cpp b/osrf_testing_tools_cpp/src/memory_tools/is_working.cpp new file mode 100644 index 0000000..7af679a --- /dev/null +++ b/osrf_testing_tools_cpp/src/memory_tools/is_working.cpp @@ -0,0 +1,55 @@ +// Copyright 2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "osrf_testing_tools_cpp/memory_tools/is_working.hpp" + +#include + +#include "osrf_testing_tools_cpp/memory_tools/register_hooks.hpp" + +namespace osrf_testing_tools_cpp +{ +namespace memory_tools +{ + +volatile char side_effect[1024]; + +void +guaranteed_malloc(const std::string & str) +{ + void * some_memory = std::malloc(1024); + // We need to do something with the malloc'ed memory to make sure this + // function doesn't get optimized away. memset isn't enough, so we do a + // memcpy from a passed in string, and then copy *that* out to an array that + // is globally visible (assuring we have a side-effect). This is enough to + // keep the optimizer away. + memcpy(some_memory, str.c_str(), str.length()); + memcpy((void *)side_effect, some_memory, str.length()); + std::free(some_memory); +} + +bool +is_working() +{ + auto original_on_malloc = get_on_malloc(); + bool malloc_was_called = false; + on_malloc([&]() {malloc_was_called = true;}); + std::string tmp("doesn't matter"); + guaranteed_malloc(tmp); + on_malloc(original_on_malloc); + return malloc_was_called; +} + +} // namespace memory_tools +} // namespace osrf_testing_tools_cpp diff --git a/test_osrf_testing_tools_cpp/CMakeLists.txt b/test_osrf_testing_tools_cpp/CMakeLists.txt index 98552e7..13470cd 100644 --- a/test_osrf_testing_tools_cpp/CMakeLists.txt +++ b/test_osrf_testing_tools_cpp/CMakeLists.txt @@ -31,5 +31,14 @@ if(BUILD_TESTING) COMMAND "$" ENV ${extra_env_vars} ) + + add_executable(test_is_not_working_gtest test/test_is_not_working.cpp) + target_link_libraries(test_is_not_working_gtest + gtest_main + osrf_testing_tools_cpp::memory_tools + ) + osrf_testing_tools_cpp_add_test(test_is_not_working_gtest + COMMAND "$" + ) endif() endif() diff --git a/test_osrf_testing_tools_cpp/test/test_example_memory_tools.cpp b/test_osrf_testing_tools_cpp/test/test_example_memory_tools.cpp index ff994ac..e5bb31b 100644 --- a/test_osrf_testing_tools_cpp/test/test_example_memory_tools.cpp +++ b/test_osrf_testing_tools_cpp/test/test_example_memory_tools.cpp @@ -21,18 +21,9 @@ #include "osrf_testing_tools_cpp/memory_tools/memory_tools.hpp" #include "osrf_testing_tools_cpp/scope_exit.hpp" -volatile char side_effect[1024]; -void my_first_function(const std::string& str) +void my_first_function(const std::string & str) { - void * some_memory = std::malloc(1024); - // We need to do something with the malloc'ed memory to make sure this - // function doesn't get optimized away. memset isn't enough, so we do a - // memcpy from a passed in string, and then copy *that* out to an array that - // is globally visible (assuring we have a side-effect). This is enough to - // keep the optimizer away. - memcpy(some_memory, str.c_str(), str.length()); - memcpy((void *)side_effect, some_memory, str.length()); - std::free(some_memory); + osrf_testing_tools_cpp::memory_tools::guaranteed_malloc(str); } int my_second_function(int a, int b) @@ -68,6 +59,7 @@ TEST(TestMemoryTools, test_example) { // enabling monitoring will allow checking to begin, but the default state is // that dynamic memory calls are expected, so again either function will pass osrf_testing_tools_cpp::memory_tools::enable_monitoring(); + ASSERT_TRUE(osrf_testing_tools_cpp::memory_tools::is_working()); my_first_function(dummy); EXPECT_EQ(my_second_function(1, 2), 3); diff --git a/test_osrf_testing_tools_cpp/test/test_is_not_working.cpp b/test_osrf_testing_tools_cpp/test/test_is_not_working.cpp new file mode 100644 index 0000000..32f4c5c --- /dev/null +++ b/test_osrf_testing_tools_cpp/test/test_is_not_working.cpp @@ -0,0 +1,32 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "osrf_testing_tools_cpp/memory_tools/memory_tools.hpp" +#include "osrf_testing_tools_cpp/scope_exit.hpp" + +TEST(TestMemoryTools, test_is_not_working) { + + // you must initialize memory tools, but uninitialization is optional + osrf_testing_tools_cpp::memory_tools::initialize(); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ + osrf_testing_tools_cpp::memory_tools::uninitialize(); + }); + + osrf_testing_tools_cpp::memory_tools::enable_monitoring(); + + ASSERT_FALSE(osrf_testing_tools_cpp::memory_tools::is_working()); +} From f58c8b93ae7fe22347abced8a1fe50bdae416517 Mon Sep 17 00:00:00 2001 From: William Woodall Date: Tue, 23 Oct 2018 16:28:54 -0700 Subject: [PATCH 3/3] address review feedback Signed-off-by: William Woodall --- .../memory_tools/is_working.hpp | 4 +++- .../test/memory_tools/test_memory_tools.cpp | 11 +---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp b/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp index ccc80da..b983f11 100644 --- a/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp +++ b/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/is_working.hpp @@ -16,6 +16,7 @@ #define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__IS_WORKING_HPP_ #include +#include #include "./visibility_control.hpp" @@ -36,8 +37,9 @@ is_working(); /// Copy an input string into allocated memory, guaranteeing malloc is called. /** * Makes sure that the compiler doesn't optimize the malloc and free out. - * Input string contents doesn't matter, but should be non-empty. + * The content of the input string doesn't matter, but should be non-empty. */ +OSRF_TESTING_TOOLS_CPP_MEMORY_TOOLS_PUBLIC void guaranteed_malloc(const std::string & str); diff --git a/osrf_testing_tools_cpp/test/memory_tools/test_memory_tools.cpp b/osrf_testing_tools_cpp/test/memory_tools/test_memory_tools.cpp index 4ed7534..2a62c7b 100644 --- a/osrf_testing_tools_cpp/test/memory_tools/test_memory_tools.cpp +++ b/osrf_testing_tools_cpp/test/memory_tools/test_memory_tools.cpp @@ -149,18 +149,9 @@ TEST(TestMemoryTools, test_allocation_checking_tools) { EXPECT_EQ(4u, unexpected_frees); } -volatile char side_effect[1024]; void my_first_function(const std::string& str) { - void * some_memory = std::malloc(1024); - // We need to do something with the malloc'ed memory to make sure this - // function doesn't get optimized away. memset isn't enough, so we do a - // memcpy from a passed in string, and then copy *that* out to an array that - // is globally visible (assuring we have a side-effect). This is enough to - // keep the optimizer away. - memcpy(some_memory, str.c_str(), str.length()); - memcpy((void *)side_effect, some_memory, str.length()); - std::free(some_memory); + osrf_testing_tools_cpp::memory_tools::guaranteed_malloc(str); } int my_second_function(int a, int b)