openssl has a memory leak detection validation test, located in test/memleaktest.c:
#include <openssl/crypto.h>
#include "testutil.h"
/* __has_feature is a clang-ism, while __SANITIZE_ADDRESS__ is a gcc-ism */
#if defined(__has_feature)
# if __has_feature(address_sanitizer)
# define __SANITIZE_ADDRESS__ 1
# endif
#endif
/* If __SANITIZE_ADDRESS__ isn't defined, define it to be false */
/* Leak detection is not yet supported with MSVC on Windows, so */
/* set __SANITIZE_ADDRESS__ to false in this case as well. */
#if !defined(__SANITIZE_ADDRESS__) || defined(_MSC_VER)
# undef __SANITIZE_ADDRESS__
# define __SANITIZE_ADDRESS__ 0
#endif
/*
* We use a proper main function here instead of the custom main from the
* test framework to avoid CRYPTO_mem_leaks stuff.
*/
int main(int argc, char *argv[])
{
#if __SANITIZE_ADDRESS__
int exitcode = EXIT_SUCCESS;
#else
/*
* When we don't sanitize, we set the exit code to what we would expect
* to get when we are sanitizing. This makes it easy for wrapper scripts
* to detect that we get the result we expect.
*/
int exitcode = EXIT_FAILURE;
#endif
char *lost;
lost = OPENSSL_malloc(3);
if (!TEST_ptr(lost))
return EXIT_FAILURE;
strcpy(lost, "ab");
if (argv[1] && strcmp(argv[1], "freeit") == 0) {
OPENSSL_free(lost);
exitcode = EXIT_SUCCESS;
}
lost = NULL;
return exitcode;
}
Compiling openssl's latest version of this code with asan enabled results in this test not detecting a memory leak that it should detect
nhorman@hmsvengance:~/git/openssl/test$ ldd ./memleaktest
linux-vdso.so.1 (0x00007fff85fd2000)
libasan.so.8 => /lib64/libasan.so.8 (0x00007f6aa7800000)
libcrypto.so.3 => /lib64/libcrypto.so.3 (0x00007f6aa7200000)
libc.so.6 => /lib64/libc.so.6 (0x00007f6aa7013000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f6aa6c00000)
libm.so.6 => /lib64/libm.so.6 (0x00007f6aa771d000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f6aa76f0000)
libz.so.1 => /lib64/libz.so.1 (0x00007f6aa7ed0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6aa7f11000)
nhorman@hmsvengance:~/git/openssl/test$ ldd ../libcrypto.so
linux-vdso.so.1 (0x00007ffff08ce000)
libasan.so.8 => /lib64/libasan.so.8 (0x00007efea5a00000)
libc.so.6 => /lib64/libc.so.6 (0x00007efea5813000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007efea5400000)
libm.so.6 => /lib64/libm.so.6 (0x00007efea6d7e000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007efea6d51000)
/lib64/ld-linux-x86-64.so.2 (0x00007efea6e7f000)
nhorman@hmsvengance:~/git/openssl/test$ LD_LIBRARY_PATH=/home/nhorman/git/openssl/ ./memleaktest
nhorman@hmsvengance:~/git/openssl/test$
Interestingly, If I change the exit code of the application such that it exits with EXIT_FAILURE rather than EXIT_SUCCESS, the leak is properly detected:
nhorman@hmsvengance:~/git/openssl/test$ LD_LIBRARY_PATH=/home/nhorman/git/openssl/ ./memleaktest
=================================================================
==11037==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 3 byte(s) in 1 object(s) allocated from:
#0 0x7f2561af68b7 in malloc (/lib64/libasan.so.8+0xf68b7) (BuildId: 9398d675390359c74744b0e7714408910d853874)
#1 0x7f25612d6be0 in CRYPTO_malloc crypto/mem.c:202
#2 0x4024b1 in main test/memleaktest.c:49
#3 0x7f2560c3d087 in __libc_start_call_main (/lib64/libc.so.6+0x2a087) (BuildId: b098f1c75a76548bb230d8f551eae07a2aeccf06)
#4 0x7f2560c3d14a in __libc_start_main_alias_2 (/lib64/libc.so.6+0x2a14a) (BuildId: b098f1c75a76548bb230d8f551eae07a2aeccf06)
#5 0x402614 in _start (/home/nhorman/git/openssl/test/memleaktest+0x402614) (BuildId: 2d89b949e7e0f801b3d552aaa03ad54083c09f1c)
SUMMARY: AddressSanitizer: 3 byte(s) leaked in 1 allocation(s).
Reproducible: Always
Steps to Reproduce:
1.build the latest version of openssl with enable-asan in the config so that -fsanitize=address is added to the CFLAGS/LDFLAGS
2. run memleaktest: LD_LIBRARY_PATH=/path/to/openssl/build ./test/memleaktest
Actual Results:
No leak is detected
Expected Results:
The leak implemented by the allocation to the lost pointer via OPENSSL_malloc should be detected