Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .evergreen/config_generator/components/funcs/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class Test(Function):
'UV_INSTALL_DIR',
'VALGRIND_INSTALL_DIR',
],
env={
'CC': '${cc_compiler}',
'CXX': '${cxx_compiler}',
},
working_dir='mongo-cxx-driver',
script='.evergreen/scripts/test.sh',
)
Expand Down
3 changes: 3 additions & 0 deletions .evergreen/generated_configs/functions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,9 @@ functions:
params:
binary: bash
working_dir: mongo-cxx-driver
env:
CC: ${cc_compiler}
CXX: ${cxx_compiler}
include_expansions_in_env:
- ASAN_SYMBOLIZER_PATH
- build_type
Expand Down
49 changes: 49 additions & 0 deletions .evergreen/scripts/bypass-dlclose.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash

# bypass_dlclose
#
# Usage:
# bypass_dlclose command args...
#
# Parameters:
# "$CC": compiler to use to compile and link the bypass_dlclose library.
#
# Return 0 (true) if able to create a shared library to bypass calls to dlclose.
# Return a non-zero (false) value otherwise.
#
# If successful, print paths to add to LD_PRELOAD to stdout (pipe 1).
# Otherwise, no output is printed to stdout (pipe 1).
#
# Diagnostic messages may be printed to stderr (pipe 2). Redirect to /dev/null
# with `2>/dev/null` to silence these messages.
bypass_dlclose() (
: "${CC:?'bypass_dlclose expects environment variable CC to be defined!'}"

declare ld_preload

{
declare tmp

if ! tmp="$(mktemp -d)"; then
echo "Could not create temporary directory for bypass_dlclose library!" 1>&2
return 1
fi

echo "int dlclose (void *handle) {(void) handle; return 0; }" \
>|"${tmp:?}/bypass_dlclose.c" || return

"${CC:?}" -o "${tmp:?}/bypass_dlclose.so" \
-shared "${tmp:?}/bypass_dlclose.c" || return

ld_preload="${tmp:?}/bypass_dlclose.so"

# Clang uses its own libasan.so; do not preload it!
if [[ ! "${CC:?}" =~ clang ]]; then
declare asan_path
asan_path="$("${CC:?}" -print-file-name=libasan.so)" || return
ld_preload="${asan_path:?}:${ld_preload:?}"
fi
} 1>&2

printf "%s" "${ld_preload:?}"
)
15 changes: 9 additions & 6 deletions .evergreen/scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ fi
export DRIVERS_TOOLS
popd # "${working_dir:?}/../drivers-evergreen-tools"

. .evergreen/scripts/bypass-dlclose.sh
. .evergreen/scripts/install-build-tools.sh
install_build_tools

Expand Down Expand Up @@ -275,21 +276,23 @@ else
)

run_test() {
echo "Running $@..."
"$@" "${test_args[@]:?}" || return
echo "Running $@... done."
echo "Running ${1:?}..."
LD_PRELOAD="${ld_preload:-}" "${1:?}" "${test_args[@]:?}" || return
echo "Running ${1:?}... done."
}

declare ld_preload="${LD_PRELOAD:-}"
if [[ "${TEST_WITH_ASAN:-}" == "ON" || "${TEST_WITH_UBSAN:-}" == "ON" ]]; then
export ASAN_OPTIONS="detect_leaks=1"
export UBSAN_OPTIONS="print_stacktrace=1"
ld_preload="$(bypass_dlclose):${ld_preload:-}"
elif [[ "${TEST_WITH_VALGRIND:-}" == "ON" ]]; then
command -V valgrind
valgrind --version
run_test() {
echo "Running $@..."
valgrind --leak-check=full --track-origins=yes --num-callers=50 --error-exitcode=1 --error-limit=no --read-var-info=yes --suppressions=../etc/memcheck.suppressions "$@" "${test_args[@]:?}" || return
echo "Running $@... done."
echo "Running ${1:?}..."
valgrind --leak-check=full --track-origins=yes --num-callers=50 --error-exitcode=1 --error-limit=no --read-var-info=yes --suppressions=../etc/memcheck.suppressions "${1:?}" "${test_args[@]:?}" || return
echo "Running ${1:?}... done."
}
fi

Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Changes prior to 3.9.0 are documented as [release notes on GitHub](https://githu
- Clang 3.8 (from Clang 3.5).
- Apple Clang 13.1 with Xcode 13.4.1 (from Apple Clang 5.1 with Xcode 5.1).
- MSVC 19.0.24210 with Visual Studio 2015 Update 3 (from MSVC 19.0.23506 with Visual Studio 2015 Update 1).
- `mongocxx::v_noabi::instance::~instance()` no longer skips calling `mongoc_cleanup()` when compiled with ASAN enabled.
- See https://github.com/google/sanitizers/issues/89 for context.

### Deprecated

Expand Down
11 changes: 0 additions & 11 deletions src/mongocxx/lib/mongocxx/v_noabi/mongocxx/instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@
#include <mongocxx/private/config/config.hh>
#include <mongocxx/private/mongoc.hh>

#if !defined(__has_feature)
#define __has_feature(x) 0
#endif

namespace mongocxx {
namespace v_noabi {

Expand Down Expand Up @@ -119,14 +115,7 @@ class instance::impl {
libmongoc::log_set_handler(null_log_handler, nullptr);
}

// Under ASAN, we don't want to clean up libmongoc, because it causes libraries to become
// unloaded, and then ASAN sees non-rooted allocations that it consideres leaks. These are
// also inscrutable, because the stack refers into an unloaded library, which ASAN can't
// report. Note that this only works if we have built mongoc so that it doesn't do its
// unfortunate automatic invocation of 'cleanup'.
#if !__has_feature(address_sanitizer)
libmongoc::cleanup();
#endif
}

impl(impl&&) noexcept = delete;
Expand Down