summaryrefslogtreecommitdiff
path: root/absl/debugging
diff options
context:
space:
mode:
Diffstat (limited to 'absl/debugging')
-rw-r--r--absl/debugging/BUILD.bazel113
-rw-r--r--absl/debugging/CMakeLists.txt72
-rw-r--r--absl/debugging/leak_check.cc44
-rw-r--r--absl/debugging/leak_check.h19
-rw-r--r--absl/debugging/leak_check_disable.cc20
-rw-r--r--absl/debugging/leak_check_test.cc17
-rw-r--r--absl/debugging/stacktrace_benchmark.cc55
7 files changed, 138 insertions, 202 deletions
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index 3c4ea8dc..7f5c1cad 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -225,6 +225,7 @@ cc_library(
name = "leak_check",
srcs = ["leak_check.cc"],
hdrs = ["leak_check.h"],
+ copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
@@ -232,98 +233,33 @@ cc_library(
],
)
-# Adding a dependency to leak_check_disable will disable
-# sanitizer leak checking (asan/lsan) in a test without
-# the need to mess around with build features.
-cc_library(
- name = "leak_check_disable",
- srcs = ["leak_check_disable.cc"],
- linkopts = ABSL_DEFAULT_LINKOPTS,
- linkstatic = 1,
- deps = ["//absl/base:config"],
- alwayslink = 1,
-)
-
-# These targets exists for use in tests only, explicitly configuring the
-# LEAK_SANITIZER macro. It must be linked with -fsanitize=leak for lsan.
-ABSL_LSAN_LINKOPTS = select({
- "//absl:clang_compiler": ["-fsanitize=leak"],
- "//conditions:default": [],
-})
-
-cc_library(
- name = "leak_check_api_enabled_for_testing",
- testonly = 1,
- srcs = ["leak_check.cc"],
- hdrs = ["leak_check.h"],
- copts = select({
- "//absl:clang_compiler": ["-DLEAK_SANITIZER"],
- "//conditions:default": [],
- }),
- linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = ["//visibility:private"],
- deps = [
- "//absl/base:config",
- "//absl/base:core_headers",
- ],
-)
-
-cc_library(
- name = "leak_check_api_disabled_for_testing",
- testonly = 1,
- srcs = ["leak_check.cc"],
- hdrs = ["leak_check.h"],
- copts = ["-ULEAK_SANITIZER"],
- linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = ["//visibility:private"],
- deps = [
- "//absl/base:config",
- "//absl/base:core_headers",
- ],
-)
-
cc_test(
name = "leak_check_test",
srcs = ["leak_check_test.cc"],
- copts = select({
- "//absl:clang_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
- "//conditions:default": [],
- }),
- linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
- tags = ["notsan"],
- deps = [
- ":leak_check_api_enabled_for_testing",
- "//absl/base",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_test(
- name = "leak_check_no_lsan_test",
- srcs = ["leak_check_test.cc"],
- copts = ["-UABSL_EXPECT_LEAK_SANITIZER"],
+ copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- tags = ["noasan"],
+ tags = ["notsan"],
deps = [
- ":leak_check_api_disabled_for_testing",
- "//absl/base", # for raw_logging
+ ":leak_check",
+ "//absl/base:config",
+ "//absl/base:raw_logging_internal",
"@com_google_googletest//:gtest_main",
],
)
-# Test that leak checking is skipped when lsan is enabled but
-# ":leak_check_disable" is linked in.
-#
-# This test should fail in the absence of a dependency on ":leak_check_disable"
-cc_test(
- name = "disabled_leak_check_test",
+# Binary that leaks memory and expects to fail on exit. This isn't a
+# test that expected to pass on its own; it exists to be called by a
+# script that checks exit status and output.
+# TODO(absl-team): Write a test to run this with a script that
+# verifies that it correctly fails.
+cc_binary(
+ name = "leak_check_fail_test_binary",
srcs = ["leak_check_fail_test.cc"],
- linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
- tags = ["notsan"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- ":leak_check_api_enabled_for_testing",
- ":leak_check_disable",
- "//absl/base",
+ ":leak_check",
+ "//absl/base:raw_logging_internal",
"@com_google_googletest//:gtest_main",
],
)
@@ -356,3 +292,18 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
+
+cc_binary(
+ name = "stacktrace_benchmark",
+ testonly = 1,
+ srcs = ["stacktrace_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ deps = [
+ ":stacktrace",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index 5850bdd0..7507ff3b 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -218,42 +218,6 @@ absl_cc_library(
PUBLIC
)
-absl_cc_library(
- NAME
- leak_check_disable
- SRCS
- "leak_check_disable.cc"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- PUBLIC
-)
-
-absl_cc_library(
- NAME
- leak_check_api_enabled_for_testing
- HDRS
- "leak_check.h"
- SRCS
- "leak_check.cc"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- $<$<BOOL:${ABSL_HAVE_LSAN}>:-DLEAK_SANITIZER>
- TESTONLY
-)
-
-absl_cc_library(
- NAME
- leak_check_api_disabled_for_testing
- HDRS
- "leak_check.h"
- SRCS
- "leak_check.cc"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- "-ULEAK_SANITIZER"
- TESTONLY
-)
-
absl_cc_test(
NAME
leak_check_test
@@ -261,43 +225,11 @@ absl_cc_test(
"leak_check_test.cc"
COPTS
${ABSL_TEST_COPTS}
- "$<$<BOOL:${ABSL_HAVE_LSAN}>:-DABSL_EXPECT_LEAK_SANITIZER>"
LINKOPTS
- "${ABSL_LSAN_LINKOPTS}"
- DEPS
- absl::leak_check_api_enabled_for_testing
- absl::base
- GTest::gmock_main
-)
-
-absl_cc_test(
- NAME
- leak_check_no_lsan_test
- SRCS
- "leak_check_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- "-UABSL_EXPECT_LEAK_SANITIZER"
- DEPS
- absl::leak_check_api_disabled_for_testing
- absl::base
- GTest::gmock_main
-)
-
-absl_cc_test(
- NAME
- disabled_leak_check_test
- SRCS
- "leak_check_fail_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- LINKOPTS
- "${ABSL_LSAN_LINKOPTS}"
+ ${ABSL_DEFAULT_LINKOPTS}
DEPS
- absl::leak_check_api_enabled_for_testing
- absl::leak_check_disable
+ absl::leak_check
absl::base
- absl::raw_logging_internal
GTest::gmock_main
)
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc
index 764ca0ad..195e82bf 100644
--- a/absl/debugging/leak_check.cc
+++ b/absl/debugging/leak_check.cc
@@ -11,29 +11,19 @@
// 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.
-
+//
// Wrappers around lsan_interface functions.
-// When lsan is not linked in, these functions are not available,
-// therefore Abseil code which depends on these functions is conditioned on the
-// definition of LEAK_SANITIZER.
-#include "absl/base/attributes.h"
-#include "absl/debugging/leak_check.h"
+//
+// These are always-available run-time functions manipulating the LeakSanitizer,
+// even when the lsan_interface (and LeakSanitizer) is not available. When
+// LeakSanitizer is not linked in, these functions become no-op stubs.
-#ifndef LEAK_SANITIZER
+#include "absl/debugging/leak_check.h"
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-bool HaveLeakSanitizer() { return false; }
-bool LeakCheckerIsActive() { return false; }
-void DoIgnoreLeak(const void*) { }
-void RegisterLivePointers(const void*, size_t) { }
-void UnRegisterLivePointers(const void*, size_t) { }
-LeakCheckDisabler::LeakCheckDisabler() { }
-LeakCheckDisabler::~LeakCheckDisabler() { }
-ABSL_NAMESPACE_END
-} // namespace absl
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
-#else
+#if defined(ABSL_HAVE_LEAK_SANITIZER)
#include <sanitizer/lsan_interface.h>
@@ -66,4 +56,18 @@ LeakCheckDisabler::~LeakCheckDisabler() { __lsan_enable(); }
ABSL_NAMESPACE_END
} // namespace absl
-#endif // LEAK_SANITIZER
+#else // defined(ABSL_HAVE_LEAK_SANITIZER)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+bool HaveLeakSanitizer() { return false; }
+bool LeakCheckerIsActive() { return false; }
+void DoIgnoreLeak(const void*) { }
+void RegisterLivePointers(const void*, size_t) { }
+void UnRegisterLivePointers(const void*, size_t) { }
+LeakCheckDisabler::LeakCheckDisabler() { }
+LeakCheckDisabler::~LeakCheckDisabler() { }
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // defined(ABSL_HAVE_LEAK_SANITIZER)
diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h
index 5fc2b052..eff162f6 100644
--- a/absl/debugging/leak_check.h
+++ b/absl/debugging/leak_check.h
@@ -24,7 +24,24 @@
// Note: this leak checking API is not yet supported in MSVC.
// Leak checking is enabled by default in all ASan builds.
//
-// See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
+// https://clang.llvm.org/docs/LeakSanitizer.html
+// https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
+//
+// GCC and Clang both automatically enable LeakSanitizer when AddressSanitizer
+// is enabled. To use the mode, simply pass `-fsanitize=address` to both the
+// compiler and linker. An example Bazel command could be
+//
+// $ bazel test --copt=-fsanitize=address --linkopt=-fsanitize=address ...
+//
+// GCC and Clang auto support a standalone LeakSanitizer mode (a mode which does
+// not also use AddressSanitizer). To use the mode, simply pass
+// `-fsanitize=leak` to both the compiler and linker. Since GCC does not
+// currently provide a way of detecting this mode at compile-time, GCC users
+// must also pass -DLEAK_SANIITIZER to the compiler. An example Bazel command
+// could be
+//
+// $ bazel test --copt=-DLEAK_SANITIZER --copt=-fsanitize=leak
+// --linkopt=-fsanitize=leak ...
//
// -----------------------------------------------------------------------------
#ifndef ABSL_DEBUGGING_LEAK_CHECK_H_
diff --git a/absl/debugging/leak_check_disable.cc b/absl/debugging/leak_check_disable.cc
deleted file mode 100644
index 924d6e3d..00000000
--- a/absl/debugging/leak_check_disable.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// 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
-//
-// https://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.
-
-// Disable LeakSanitizer when this file is linked in.
-// This function overrides __lsan_is_turned_off from sanitizer/lsan_interface.h
-extern "C" int __lsan_is_turned_off();
-extern "C" int __lsan_is_turned_off() {
- return 1;
-}
diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc
index 9fcfc8e5..6a42e31b 100644
--- a/absl/debugging/leak_check_test.cc
+++ b/absl/debugging/leak_check_test.cc
@@ -15,27 +15,24 @@
#include <string>
#include "gtest/gtest.h"
+#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/debugging/leak_check.h"
namespace {
-TEST(LeakCheckTest, DetectLeakSanitizer) {
-#ifdef ABSL_EXPECT_LEAK_SANITIZER
- EXPECT_TRUE(absl::HaveLeakSanitizer());
- EXPECT_TRUE(absl::LeakCheckerIsActive());
-#else
- EXPECT_FALSE(absl::HaveLeakSanitizer());
- EXPECT_FALSE(absl::LeakCheckerIsActive());
-#endif
-}
-
TEST(LeakCheckTest, IgnoreLeakSuppressesLeakedMemoryErrors) {
+ if (!absl::LeakCheckerIsActive()) {
+ GTEST_SKIP() << "LeakChecker is not active";
+ }
auto foo = absl::IgnoreLeak(new std::string("some ignored leaked string"));
ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str());
}
TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) {
+ if (!absl::LeakCheckerIsActive()) {
+ GTEST_SKIP() << "LeakChecker is not active";
+ }
absl::LeakCheckDisabler disabler;
auto foo = new std::string("some string leaked while checks are disabled");
ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str());
diff --git a/absl/debugging/stacktrace_benchmark.cc b/absl/debugging/stacktrace_benchmark.cc
new file mode 100644
index 00000000..9360bafe
--- /dev/null
+++ b/absl/debugging/stacktrace_benchmark.cc
@@ -0,0 +1,55 @@
+// Copyright 2022 The Abseil Authors
+//
+// 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
+//
+// https://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 "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+#include "absl/debugging/stacktrace.h"
+#include "benchmark/benchmark.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+static constexpr int kMaxStackDepth = 100;
+static constexpr int kCacheSize = (1 << 16);
+void* pcs[kMaxStackDepth];
+
+ABSL_ATTRIBUTE_NOINLINE void func(benchmark::State& state, int x, int depth) {
+ if (x <= 0) {
+ // Touch a significant amount of memory so that the stack is likely to be
+ // not cached in the L1 cache.
+ state.PauseTiming();
+ int* arr = new int[kCacheSize];
+ for (int i = 0; i < kCacheSize; ++i) benchmark::DoNotOptimize(arr[i] = 100);
+ delete[] arr;
+ state.ResumeTiming();
+ benchmark::DoNotOptimize(absl::GetStackTrace(pcs, depth, 0));
+ return;
+ }
+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+ func(state, --x, depth);
+}
+
+void BM_GetStackTrace(benchmark::State& state) {
+ int depth = state.range(0);
+ for (auto s : state) {
+ func(state, depth, depth);
+ }
+}
+
+BENCHMARK(BM_GetStackTrace)->DenseRange(10, kMaxStackDepth, 10);
+} // namespace
+ABSL_NAMESPACE_END
+} // namespace absl