8298445: Add LeakSanitizer support in HotSpot

Reviewed-by: erikj, ihse
This commit is contained in:
Justin King 2023-02-07 17:41:25 +00:00 committed by Magnus Ihse Bursie
parent 2e2e71e1fa
commit 27126157d9
22 changed files with 344 additions and 7 deletions

View File

@ -219,6 +219,9 @@ JDKOPT_SETUP_ADDRESS_SANITIZER
# UndefinedBehaviorSanitizer
JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER
# LeakSanitizer
JDKOPT_SETUP_LEAK_SANITIZER
###############################################################################
#
# Check dependencies for external and internal libraries.

View File

@ -440,6 +440,39 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER],
AC_SUBST(ASAN_ENABLED)
])
###############################################################################
#
# LeakSanitizer
#
AC_DEFUN_ONCE([JDKOPT_SETUP_LEAK_SANITIZER],
[
UTIL_ARG_ENABLE(NAME: lsan, DEFAULT: false, RESULT: LSAN_ENABLED,
DESC: [enable LeakSanitizer],
CHECK_AVAILABLE: [
AC_MSG_CHECKING([if LeakSanitizer (lsan) is available])
if test "x$TOOLCHAIN_TYPE" = "xgcc" ||
test "x$TOOLCHAIN_TYPE" = "xclang"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AVAILABLE=false
fi
],
IF_ENABLED: [
LSAN_CFLAGS="-fsanitize=leak -fno-omit-frame-pointer -DLEAK_SANITIZER"
LSAN_LDFLAGS="-fsanitize=leak"
JVM_CFLAGS="$JVM_CFLAGS $LSAN_CFLAGS"
JVM_LDFLAGS="$JVM_LDFLAGS $LSAN_LDFLAGS"
CFLAGS_JDKLIB="$CFLAGS_JDKLIB $LSAN_CFLAGS"
CFLAGS_JDKEXE="$CFLAGS_JDKEXE $LSAN_CFLAGS"
CXXFLAGS_JDKLIB="$CXXFLAGS_JDKLIB $LSAN_CFLAGS"
CXXFLAGS_JDKEXE="$CXXFLAGS_JDKEXE $LSAN_CFLAGS"
LDFLAGS_JDKLIB="$LDFLAGS_JDKLIB $LSAN_LDFLAGS"
LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE $LSAN_LDFLAGS"
])
AC_SUBST(LSAN_ENABLED)
])
###############################################################################
#
# UndefinedBehaviorSanitizer

View File

@ -448,6 +448,9 @@ JCOV_FILTERS=@JCOV_FILTERS@
# AddressSanitizer
ASAN_ENABLED:=@ASAN_ENABLED@
# LeakSanitizer
LSAN_ENABLED:=@LSAN_ENABLED@
# UndefinedBehaviorSanitizer
UBSAN_ENABLED:=@UBSAN_ENABLED@
UBSAN_CFLAGS:=@UBSAN_CFLAGS@

View File

@ -150,6 +150,10 @@ define SetupBuildLauncherBody
$1_EXTRA_FILES += $(TOPDIR)/make/data/asan/asan_default_options.c
endif
ifeq ($(LSAN_ENABLED), true)
$1_EXTRA_FILES += $(TOPDIR)/make/data/lsan/lsan_default_options.c
endif
$$(eval $$(call SetupJdkExecutable, BUILD_LAUNCHER_$1, \
NAME := $1, \
EXTRA_FILES := $$($1_EXTRA_FILES), \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, Google and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -50,8 +50,16 @@
// used. You can override these options by setting the environment variable ASAN_OPTIONS.
ATTRIBUTE_DEFAULT_VISIBILITY ATTRIBUTE_USED const char* __asan_default_options() {
return
#ifndef LEAK_SANITIZER
#ifdef LEAK_SANITIZER
"leak_check_at_exit=0,"
#else
// ASan bundles LSan, however we only support LSan when it is explicitly requested during
// configuration. Thus we disable it to match if it was not requested.
"detect_leaks=0,"
#endif
"handle_segv=0";
"print_suppressions=0,"
"handle_segv=0,"
// See https://github.com/google/sanitizers/issues/1322. Hopefully this is resolved
// at some point and we can remove this option.
"intercept_tls_get_addr=0";
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, Google and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2023, Google and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef LEAK_SANITIZER
#error "Build misconfigured, preprocessor macro LEAK_SANITIZER should be defined"
#endif
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(visibility)
#define ATTRIBUTE_DEFAULT_VISIBILITY __attribute__((visibility("default")))
#else
#define ATTRIBUTE_DEFAULT_VISIBILITY
#endif
#if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(used)
#define ATTRIBUTE_USED __attribute__((used))
#else
#define ATTRIBUTE_USED
#endif
// Override weak symbol exposed by LSan to override default options. This is called by LSan
// extremely early during library loading, before main is called. We need to override the default
// options because LSan will perform leak checking at program exit. Unfortunately Hotspot does not
// shutdown cleanly at the moment and some leaks occur, we want to ignore these. Instead we
// explicitly perform leak checking early during JVM shutdown.
ATTRIBUTE_DEFAULT_VISIBILITY ATTRIBUTE_USED const char* __lsan_default_options() {
return
"print_suppressions=0,"
"leak_check_at_exit=0,"
// See https://github.com/google/sanitizers/issues/1322. Hopefully this is resolved
// at some point and we can remove this option.
"intercept_tls_get_addr=0";
}
// Override weak symbol exposed by LSan to override default suppressions. This is called by LSan
// extremely early during library loading, before main is called.
ATTRIBUTE_DEFAULT_VISIBILITY ATTRIBUTE_USED const char* __lsan_default_suppressions() {
return
// Remove after JDK-8297688 is resolved.
"leak:^JLI_MemAlloc$\n"
"leak:^JLI_StringDup$\n";
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2023, Google and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
extern "C" {
#include "./lsan_default_options.c"
} // extern "C"

View File

@ -32,6 +32,10 @@ ifeq ($(ASAN_ENABLED), true)
GTEST_LAUNCHER_SRC += $(TOPDIR)/make/data/asan/asan_default_options.cpp
endif
ifeq ($(LSAN_ENABLED), true)
GTEST_LAUNCHER_SRC += $(TOPDIR)/make/data/lsan/lsan_default_options.cpp
endif
# On Windows, there are no internal debug symbols so must set copying to true
# to get any at all.
ifeq ($(call isTargetOs, windows), true)

View File

@ -1521,7 +1521,13 @@ endif
ifeq ($(ASAN_ENABLED), true)
# Any executable which launches the JVM and uses a custom launcher needs to explicitly link in the
# default ASan options.
BUILD_HOTSPOT_JTREG_EXTRA_FILES := $(TOPDIR)/make/data/asan/asan_default_options.c
BUILD_HOTSPOT_JTREG_EXTRA_FILES += $(TOPDIR)/make/data/asan/asan_default_options.c
endif
ifeq ($(LSAN_ENABLED), true)
# Any executable which launches the JVM and uses a custom launcher needs to explicitly link in the
# default LSan options.
BUILD_HOTSPOT_JTREG_EXTRA_FILES += $(TOPDIR)/make/data/lsan/lsan_default_options.c
endif
# This evaluation is expensive and should only be done if this target was

View File

@ -135,7 +135,13 @@ endif
ifeq ($(ASAN_ENABLED), true)
# Any executable which launches the JVM and uses a custom launcher needs to explicitly link in the
# default ASan options.
BUILD_JDK_JTREG_EXTRA_FILES := $(TOPDIR)/make/data/asan/asan_default_options.c
BUILD_JDK_JTREG_EXTRA_FILES += $(TOPDIR)/make/data/asan/asan_default_options.c
endif
ifeq ($(LSAN_ENABLED), true)
# Any executable which launches the JVM and uses a custom launcher needs to explicitly link in the
# default LSan options.
BUILD_JDK_JTREG_EXTRA_FILES += $(TOPDIR)/make/data/lsan/lsan_default_options.c
endif
# This evaluation is expensive and should only be done if this target was

View File

@ -40,6 +40,7 @@
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/vm_version.hpp"
#include "sanitizers/leak.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/macros.hpp"
@ -50,6 +51,8 @@ Compiler::Compiler() : AbstractCompiler(compiler_c1) {
void Compiler::init_c1_runtime() {
BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
Arena* arena = new (mtCompiler) Arena(mtCompiler);
// Ignore leaked arena, it is used by ValueType and Interval during initialization.
LSAN_IGNORE_OBJECT(arena);
Runtime1::initialize(buffer_blob);
FrameMap::initialize();
// initialize data structures

View File

@ -75,6 +75,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vmOperations.hpp"
#include "sanitizers/leak.hpp"
#include "services/memTracker.hpp"
#include "utilities/align.hpp"
#include "utilities/bitMap.inline.hpp"
@ -990,6 +991,8 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
bool dynamic_mapped = (dynamic_mapinfo != nullptr && dynamic_mapinfo->is_mapped());
char* cds_base = static_mapinfo->mapped_base();
char* cds_end = dynamic_mapped ? dynamic_mapinfo->mapped_end() : static_mapinfo->mapped_end();
// Register CDS memory region with LSan.
LSAN_REGISTER_ROOT_REGION(cds_base, cds_end - cds_base);
set_shared_metaspace_range(cds_base, static_mapinfo->mapped_end(), cds_end);
_relocation_delta = static_mapinfo->relocation_delta();
_requested_base_address = static_mapinfo->requested_base_address();

View File

@ -62,6 +62,7 @@
#include "runtime/os.inline.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/vmThread.hpp"
#include "sanitizers/leak.hpp"
#include "services/memoryService.hpp"
#include "utilities/align.hpp"
#include "utilities/vmError.hpp"
@ -329,6 +330,9 @@ void CodeCache::initialize_heaps() {
ReservedSpace non_method_space = rest.first_part(non_nmethod_size);
ReservedSpace non_profiled_space = rest.last_part(non_nmethod_size);
// Register CodeHeaps with LSan as we sometimes embed pointers to malloc memory.
LSAN_REGISTER_ROOT_REGION(rs.base(), rs.size());
// Non-nmethods (stubs, adapters, ...)
add_heap(non_method_space, "CodeHeap 'non-nmethods'", CodeBlobType::NonNMethod);
// Tier 2 and tier 3 (profiled) methods
@ -1194,6 +1198,8 @@ void CodeCache::initialize() {
FLAG_SET_ERGO(ProfiledCodeHeapSize, 0);
FLAG_SET_ERGO(NonProfiledCodeHeapSize, 0);
ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize);
// Register CodeHeaps with LSan as we sometimes embed pointers to malloc memory.
LSAN_REGISTER_ROOT_REGION(rs.base(), rs.size());
add_heap(rs, "CodeCache", CodeBlobType::All);
}

View File

@ -45,6 +45,7 @@
#include "runtime/safepoint.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "sanitizers/leak.hpp"
#include "utilities/events.hpp"
@ -272,6 +273,9 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod
needs_ic_stub_refill = true;
return false;
}
// LSan appears unable to follow malloc-based memory consistently when embedded as an immediate
// in generated machine code. So we have to ignore it.
LSAN_IGNORE_OBJECT(holder);
} else {
assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable");
// Can be different than selected_method->vtable_index(), due to package-private etc.
@ -442,6 +446,9 @@ bool CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
delete holder;
return false;
}
// LSan appears unable to follow malloc-based memory consistently when embedded as an
// immediate in generated machine code. So we have to ignore it.
LSAN_IGNORE_OBJECT(holder);
if (TraceICs) {
ResourceMark rm(thread);
tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to interpreter via icholder ", p2i(instruction_address()));

View File

@ -43,6 +43,7 @@
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "sanitizers/address.hpp"
#include "sanitizers/leak.hpp"
#include "services/memTracker.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
@ -239,6 +240,10 @@ VirtualSpaceNode::VirtualSpaceNode(ReservedSpace rs, bool owns_rs, CommitLimiter
// Poison the memory region. It will be unpoisoned later on a per-chunk base for chunks that are
// handed to arenas.
ASAN_POISON_MEMORY_REGION(rs.base(), rs.size());
// Register memory region related to Metaspace. The Metaspace contains lots of pointers to malloc
// memory.
LSAN_REGISTER_ROOT_REGION(rs.base(), rs.size());
}
// Create a node of a given size (it will create its own space).
@ -270,11 +275,15 @@ VirtualSpaceNode* VirtualSpaceNode::create_node(ReservedSpace rs, CommitLimiter*
VirtualSpaceNode::~VirtualSpaceNode() {
DEBUG_ONLY(verify_locked();)
// Unregister memory region related to Metaspace.
LSAN_UNREGISTER_ROOT_REGION(_rs.base(), _rs.size());
// Undo the poisoning before potentially unmapping memory. This ensures that future mappings at
// the same address do not unexpectedly fail with use-after-poison.
ASAN_UNPOISON_MEMORY_REGION(_rs.base(), _rs.size());
UL(debug, ": dies.");
if (_owns_rs) {
_rs.release();
}

View File

@ -75,6 +75,7 @@
#include "runtime/jniHandles.hpp"
#include "runtime/threads.hpp"
#include "runtime/timerTrace.hpp"
#include "sanitizers/leak.hpp"
#include "services/memoryService.hpp"
#include "utilities/align.hpp"
#include "utilities/autoRestore.hpp"
@ -751,7 +752,11 @@ bool Universe::contains_non_oop_word(void* p) {
}
static void initialize_global_behaviours() {
CompiledICProtectionBehaviour::set_current(new DefaultICProtectionBehaviour());
DefaultICProtectionBehaviour* protection_behavior = new DefaultICProtectionBehaviour();
// Ignore leak of DefaultICProtectionBehaviour. It is overriden by some GC implementations and the
// pointer is leaked once.
LSAN_IGNORE_OBJECT(protection_behavior);
CompiledICProtectionBehaviour::set_current(protection_behavior);
}
jint universe_init() {

View File

@ -59,6 +59,7 @@
#include "runtime/safepointVerifiers.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
#include "sanitizers/leak.hpp"
#include "utilities/exceptions.hpp"
@ -983,6 +984,8 @@ void MethodHandles::trace_method_handle_interpreter_entry(MacroAssembler* _masm,
}
jio_snprintf(qname, len, "MethodHandle::interpreter_entry::%s%s", name, suffix);
trace_method_handle(_masm, qname);
// LSan appears unable to keep track of qname, ignore it.
LSAN_IGNORE_OBJECT(qname);
// Note: Don't free the allocated char array because it's used
// during runtime.
}

View File

@ -28,6 +28,7 @@
#include "code/icBuffer.hpp"
#include "compiler/compiler_globals.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/gcHeapSummary.hpp"
#include "interpreter/bytecodes.hpp"
#include "logging/logAsyncWriter.hpp"
#include "memory/universe.hpp"
@ -43,6 +44,7 @@
#include "runtime/init.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/sharedRuntime.hpp"
#include "sanitizers/leak.hpp"
#include "services/memTracker.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JVMCI
@ -123,6 +125,14 @@ jint init_globals() {
if (status != JNI_OK)
return status;
#ifdef LEAK_SANITIZER
{
// Register the Java heap with LSan.
VirtualSpaceSummary summary = Universe::heap()->create_heap_space_summary();
LSAN_REGISTER_ROOT_REGION(summary.start(), summary.reserved_size());
}
#endif // LEAK_SANITIZER
AsyncLogWriter::initialize();
gc_barrier_stubs_init(); // depends on universe_init, must be before interpreter_init
continuations_init(); // must precede continuation stub generation
@ -183,6 +193,13 @@ void exit_globals() {
StringTable::dump(tty);
}
ostream_exit();
#ifdef LEAK_SANITIZER
{
// Unregister the Java heap with LSan.
VirtualSpaceSummary summary = Universe::heap()->create_heap_space_summary();
LSAN_UNREGISTER_ROOT_REGION(summary.start(), summary.reserved_size());
}
#endif // LEAK_SANITIZER
}
}

View File

@ -72,6 +72,7 @@
#include "runtime/vmOperations.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_version.hpp"
#include "sanitizers/leak.hpp"
#include "services/memTracker.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/globalDefinitions.hpp"
@ -416,6 +417,30 @@ void before_exit(JavaThread* thread, bool halt) {
}
}
// At this point only one thread is executing this logic. Any other threads
// attempting to invoke before_exit() will wait above and return early once
// this thread finishes before_exit().
// Do not add any additional shutdown logic between the above mutex logic and
// leak sanitizer logic below. Any additional shutdown code which performs some
// cleanup should be added after the leak sanitizer logic below.
#ifdef LEAK_SANITIZER
// If we are built with LSan, we need to perform leak checking. If we are
// terminating normally, not halting and no VM error, we perform a normal
// leak check which terminates if leaks are found. If we are not terminating
// normally, halting or VM error, we perform a recoverable leak check which
// prints leaks but will not terminate.
if (!halt && !VMError::is_error_reported()) {
LSAN_DO_LEAK_CHECK();
} else {
// Ignore the return value.
static_cast<void>(LSAN_DO_RECOVERABLE_LEAK_CHECK());
}
#endif
// Actual shutdown logic begins here.
#if INCLUDE_JVMCI
if (EnableJVMCI) {
JVMCI::shutdown(thread);

View File

@ -33,6 +33,7 @@
#include "runtime/nonJavaThread.hpp"
#include "runtime/osThread.hpp"
#include "runtime/task.hpp"
#include "sanitizers/leak.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/singleWriterSynchronizer.hpp"
#include "utilities/vmError.hpp"
@ -285,6 +286,7 @@ void WatcherThread::run() {
// Signal that it is terminated
{
MutexLocker mu(Terminator_lock, Mutex::_no_safepoint_check_flag);
LSAN_IGNORE_OBJECT(_watcher_thread);
_watcher_thread = nullptr;
Terminator_lock->notify_all();
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2023, Google and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_SANITIZERS_LEAK_HPP
#define SHARE_SANITIZERS_LEAK_HPP
#ifdef LEAK_SANITIZER
#include <sanitizer/lsan_interface.h>
#endif
// LSAN_REGISTER_ROOT_REGION()/LSAN_UNREGISTER_ROOT_REGION()
//
// Register/unregister regions of memory with LSan. LSan scans these regions looking for
// pointers to malloc memory. This is only necessary when pointers to malloc memory are
// located in memory that is not returned by malloc, such as mapped memory. LSan will
// skip inaccessible parts of the region, such as those that are not readable.
#ifdef LEAK_SANITIZER
#define LSAN_REGISTER_ROOT_REGION(addr, size) __lsan_register_root_region((addr), (size))
#define LSAN_UNREGISTER_ROOT_REGION(addr, size) __lsan_unregister_root_region((addr), (size))
#else
#define LSAN_REGISTER_ROOT_REGION(addr, size) \
do { \
if (false) { \
((void) (addr)); \
((void) (size)); \
} \
} while (false)
#define LSAN_UNREGISTER_ROOT_REGION(addr, size) \
do { \
if (false) { \
((void) (addr)); \
((void) (size)); \
} \
} while (false)
#endif
// LSAN_IGNORE_OBJECT()
//
// Causes LSan to ignore any leaks related to the object. Should only be used
// in cases where leaks are intentional or where LSan will be unable to discover
// pointers to object, for example due to pointers being stored unaligned.
#ifdef LEAK_SANITIZER
#define LSAN_IGNORE_OBJECT(object) __lsan_ignore_object(object)
#else
#define LSAN_IGNORE_OBJECT(object) \
do { \
if (false) { \
((void) (object)); \
} \
} while (false)
#endif
// LSAN_DO_LEAK_CHECK()
//
// Perform a leak check, terminating the process if leaks are found. LSan will
// skip performing leak checks at process exit and further calls will be ignored.
#ifdef LEAK_SANITIZER
#define LSAN_DO_LEAK_CHECK() __lsan_do_leak_check()
#else
#define LSAN_DO_LEAK_CHECK() ((void) 0)
#endif
// LSAN_DO_RECOVERABLE_LEAK_CHECK()
//
// Perform a leak check without terminating if leaks are found.
#ifdef LEAK_SANITIZER
#define LSAN_DO_RECOVERABLE_LEAK_CHECK() __lsan_do_recoverable_leak_check()
#else
#define LSAN_DO_RECOVERABLE_LEAK_CHECK() ((int) 0)
#endif
#endif // SHARE_SANITIZERS_ADDRESS_HPP