Skip to content

Commit 7f8ea7b

Browse files
authored
Move ASAN workaround from mongocxx::instance to CI with bypass_dlclose (#1453)
1 parent 37df792 commit 7f8ea7b

File tree

6 files changed

+67
-17
lines changed

6 files changed

+67
-17
lines changed

.evergreen/config_generator/components/funcs/test.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class Test(Function):
4242
'UV_INSTALL_DIR',
4343
'VALGRIND_INSTALL_DIR',
4444
],
45+
env={
46+
'CC': '${cc_compiler}',
47+
'CXX': '${cxx_compiler}',
48+
},
4549
working_dir='mongo-cxx-driver',
4650
script='.evergreen/scripts/test.sh',
4751
)

.evergreen/generated_configs/functions.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ functions:
653653
params:
654654
binary: bash
655655
working_dir: mongo-cxx-driver
656+
env:
657+
CC: ${cc_compiler}
658+
CXX: ${cxx_compiler}
656659
include_expansions_in_env:
657660
- ASAN_SYMBOLIZER_PATH
658661
- build_type
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env bash
2+
3+
# bypass_dlclose
4+
#
5+
# Usage:
6+
# bypass_dlclose command args...
7+
#
8+
# Parameters:
9+
# "$CC": compiler to use to compile and link the bypass_dlclose library.
10+
#
11+
# Return 0 (true) if able to create a shared library to bypass calls to dlclose.
12+
# Return a non-zero (false) value otherwise.
13+
#
14+
# If successful, print paths to add to LD_PRELOAD to stdout (pipe 1).
15+
# Otherwise, no output is printed to stdout (pipe 1).
16+
#
17+
# Diagnostic messages may be printed to stderr (pipe 2). Redirect to /dev/null
18+
# with `2>/dev/null` to silence these messages.
19+
bypass_dlclose() (
20+
: "${CC:?'bypass_dlclose expects environment variable CC to be defined!'}"
21+
22+
declare ld_preload
23+
24+
{
25+
declare tmp
26+
27+
if ! tmp="$(mktemp -d)"; then
28+
echo "Could not create temporary directory for bypass_dlclose library!" 1>&2
29+
return 1
30+
fi
31+
32+
echo "int dlclose (void *handle) {(void) handle; return 0; }" \
33+
>|"${tmp:?}/bypass_dlclose.c" || return
34+
35+
"${CC:?}" -o "${tmp:?}/bypass_dlclose.so" \
36+
-shared "${tmp:?}/bypass_dlclose.c" || return
37+
38+
ld_preload="${tmp:?}/bypass_dlclose.so"
39+
40+
# Clang uses its own libasan.so; do not preload it!
41+
if [[ ! "${CC:?}" =~ clang ]]; then
42+
declare asan_path
43+
asan_path="$("${CC:?}" -print-file-name=libasan.so)" || return
44+
ld_preload="${asan_path:?}:${ld_preload:?}"
45+
fi
46+
} 1>&2
47+
48+
printf "%s" "${ld_preload:?}"
49+
)

.evergreen/scripts/test.sh

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ fi
101101
export DRIVERS_TOOLS
102102
popd # "${working_dir:?}/../drivers-evergreen-tools"
103103

104+
. .evergreen/scripts/bypass-dlclose.sh
104105
. .evergreen/scripts/install-build-tools.sh
105106
install_build_tools
106107

@@ -275,21 +276,23 @@ else
275276
)
276277

277278
run_test() {
278-
echo "Running $@..."
279-
"$@" "${test_args[@]:?}" || return
280-
echo "Running $@... done."
279+
echo "Running ${1:?}..."
280+
LD_PRELOAD="${ld_preload:-}" "${1:?}" "${test_args[@]:?}" || return
281+
echo "Running ${1:?}... done."
281282
}
282283

284+
declare ld_preload="${LD_PRELOAD:-}"
283285
if [[ "${TEST_WITH_ASAN:-}" == "ON" || "${TEST_WITH_UBSAN:-}" == "ON" ]]; then
284286
export ASAN_OPTIONS="detect_leaks=1"
285287
export UBSAN_OPTIONS="print_stacktrace=1"
288+
ld_preload="$(bypass_dlclose):${ld_preload:-}"
286289
elif [[ "${TEST_WITH_VALGRIND:-}" == "ON" ]]; then
287290
command -V valgrind
288291
valgrind --version
289292
run_test() {
290-
echo "Running $@..."
291-
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
292-
echo "Running $@... done."
293+
echo "Running ${1:?}..."
294+
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
295+
echo "Running ${1:?}... done."
293296
}
294297
fi
295298

CHANGELOG.md

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

2830
### Deprecated
2931

src/mongocxx/lib/mongocxx/v_noabi/mongocxx/instance.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@
3030
#include <mongocxx/private/config/config.hh>
3131
#include <mongocxx/private/mongoc.hh>
3232

33-
#if !defined(__has_feature)
34-
#define __has_feature(x) 0
35-
#endif
36-
3733
namespace mongocxx {
3834
namespace v_noabi {
3935

@@ -119,14 +115,7 @@ class instance::impl {
119115
libmongoc::log_set_handler(null_log_handler, nullptr);
120116
}
121117

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

132121
impl(impl&&) noexcept = delete;

0 commit comments

Comments
 (0)