From f5f3dfd5efcc1e4073719f788ed4c40f8dc8cf3b Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 15 Nov 2018 17:41:06 +0000 Subject: [PATCH] Test atexit handlers Test that atexit handlers get called properly at process exit, unless we have explicitly asked for them not to be. Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/7983) --- test/recipes/90-test_shlibload.t | 45 ++++++++++++++++++++----- test/shlibloadtest.c | 56 ++++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/test/recipes/90-test_shlibload.t b/test/recipes/90-test_shlibload.t index 2761d58502..f4bca8b73b 100644 --- a/test/recipes/90-test_shlibload.t +++ b/test/recipes/90-test_shlibload.t @@ -8,6 +8,7 @@ use OpenSSL::Test qw/:DEFAULT bldtop_dir bldtop_file/; use OpenSSL::Test::Utils; +use File::Temp qw(tempfile); #Load configdata.pm @@ -20,7 +21,7 @@ use configdata; plan skip_all => "Test only supported in a shared build" if disabled("shared"); plan skip_all => "Test is disabled on AIX" if config('target') =~ m|^aix|; -plan tests => 4; +plan tests => 10; # When libssl and libcrypto are compiled on Linux with "-rpath", but not # "--enable-new-dtags", the RPATH takes precedence over LD_LIBRARY_PATH, @@ -30,14 +31,31 @@ plan tests => 4; my $libcrypto = bldtop_file(shlib('libcrypto')); my $libssl = bldtop_file(shlib('libssl')); -ok(run(test(["shlibloadtest", "-crypto_first", $libcrypto, $libssl])), - "running shlibloadtest -crypto_first"); -ok(run(test(["shlibloadtest", "-ssl_first", $libcrypto, $libssl])), - "running shlibloadtest -ssl_first"); -ok(run(test(["shlibloadtest", "-just_crypto", $libcrypto, $libssl])), - "running shlibloadtest -just_crypto"); -ok(run(test(["shlibloadtest", "-dso_ref", $libcrypto, $libssl])), - "running shlibloadtest -dso_ref"); +(my $fh, my $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-crypto_first", $libcrypto, $libssl, $filename])), + "running shlibloadtest -crypto_first $filename"); +ok(check_atexit($fh)); +unlink $filename; +($fh, $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-ssl_first", $libcrypto, $libssl, $filename])), + "running shlibloadtest -ssl_first $filename"); +ok(check_atexit($fh)); +unlink $filename; +($fh, $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-just_crypto", $libcrypto, $libssl, $filename])), + "running shlibloadtest -just_crypto $filename"); +ok(check_atexit($fh)); +unlink $filename; +($fh, $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-dso_ref", $libcrypto, $libssl, $filename])), + "running shlibloadtest -dso_ref $filename"); +ok(check_atexit($fh)); +unlink $filename; +($fh, $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-no_atexit", $libcrypto, $libssl, $filename])), + "running shlibloadtest -no_atexit $filename"); +ok(!check_atexit($fh)); +unlink $filename; sub shlib { my $lib = shift; @@ -50,3 +68,12 @@ sub shlib { |.$config{shlib_version_number}|x; return $lib; } + +sub check_atexit { + my $fh = shift; + my $data = <$fh>; + + return 1 if (defined $data && $data =~ m/atexit\(\) run/); + + return 0; +} diff --git a/test/shlibloadtest.c b/test/shlibloadtest.c index 11dd905b8a..aebaee92c4 100644 --- a/test/shlibloadtest.c +++ b/test/shlibloadtest.c @@ -20,6 +20,8 @@ typedef void DSO; typedef const SSL_METHOD * (*TLS_method_t)(void); typedef SSL_CTX * (*SSL_CTX_new_t)(const SSL_METHOD *meth); typedef void (*SSL_CTX_free_t)(SSL_CTX *); +typedef int (*OPENSSL_init_crypto_t)(uint64_t, void *); +typedef int (*OPENSSL_atexit_t)(void (*handler)(void)); typedef unsigned long (*ERR_get_error_t)(void); typedef unsigned long (*OpenSSL_version_num_t)(void); typedef DSO * (*DSO_dsobyaddr_t)(void (*addr)(void), int flags); @@ -29,12 +31,14 @@ typedef enum test_types_en { CRYPTO_FIRST, SSL_FIRST, JUST_CRYPTO, - DSO_REFTEST + DSO_REFTEST, + NO_ATEXIT } TEST_TYPE; static TEST_TYPE test_type; static const char *path_crypto; static const char *path_ssl; +static const char *path_atexit; #ifdef DSO_DLFCN @@ -98,6 +102,17 @@ static int shlib_close(SHLIB lib) #if defined(DSO_DLFCN) || defined(DSO_WIN32) +static void atexit_handler(void) +{ + FILE *atexit_file = fopen(path_atexit, "w"); + + if (atexit_file == NULL) + return; + + fprintf(atexit_file, "atexit() run\n"); + fclose(atexit_file); +} + static int test_lib(void) { SHLIB ssllib = SHLIB_INIT; @@ -112,11 +127,13 @@ static int test_lib(void) SSL_CTX_free_t mySSL_CTX_free; ERR_get_error_t myERR_get_error; OpenSSL_version_num_t myOpenSSL_version_num; + OPENSSL_atexit_t myOPENSSL_atexit; int result = 0; switch (test_type) { case JUST_CRYPTO: case DSO_REFTEST: + case NO_ATEXIT: case CRYPTO_FIRST: if (!shlib_load(path_crypto, &cryptolib)) { fprintf(stderr, "Failed to load libcrypto\n"); @@ -140,7 +157,23 @@ static int test_lib(void) break; } - if (test_type != JUST_CRYPTO && test_type != DSO_REFTEST) { + if (test_type == NO_ATEXIT) { + OPENSSL_init_crypto_t myOPENSSL_init_crypto; + + if (!shlib_sym(cryptolib, "OPENSSL_init_crypto", &symbols[0].sym)) { + fprintf(stderr, "Failed to load OPENSSL_init_crypto symbol\n"); + goto end; + } + myOPENSSL_init_crypto = (OPENSSL_init_crypto_t)symbols[0].func; + if (!myOPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL)) { + fprintf(stderr, "Failed to initialise libcrypto\n"); + goto end; + } + } + + if (test_type != JUST_CRYPTO + && test_type != DSO_REFTEST + && test_type != NO_ATEXIT) { if (!shlib_sym(ssllib, "TLS_method", &symbols[0].sym) || !shlib_sym(ssllib, "SSL_CTX_new", &symbols[1].sym) || !shlib_sym(ssllib, "SSL_CTX_free", &symbols[2].sym)) { @@ -159,7 +192,8 @@ static int test_lib(void) } if (!shlib_sym(cryptolib, "ERR_get_error", &symbols[0].sym) - || !shlib_sym(cryptolib, "OpenSSL_version_num", &symbols[1].sym)) { + || !shlib_sym(cryptolib, "OpenSSL_version_num", &symbols[1].sym) + || !shlib_sym(cryptolib, "OPENSSL_atexit", &symbols[2].sym)) { fprintf(stderr, "Failed to load libcrypto symbols\n"); goto end; } @@ -175,6 +209,12 @@ static int test_lib(void) goto end; } + myOPENSSL_atexit = (OPENSSL_atexit_t)symbols[2].func; + if (!myOPENSSL_atexit(atexit_handler)) { + fprintf(stderr, "Failed to register atexit handler\n"); + goto end; + } + if (test_type == DSO_REFTEST) { # ifdef DSO_DLFCN DSO_dsobyaddr_t myDSO_dsobyaddr; @@ -213,6 +253,7 @@ static int test_lib(void) switch (test_type) { case JUST_CRYPTO: case DSO_REFTEST: + case NO_ATEXIT: case CRYPTO_FIRST: if (!shlib_close(cryptolib)) { fprintf(stderr, "Failed to close libcrypto\n"); @@ -253,8 +294,8 @@ int main(int argc, char *argv[]) { const char *p; - if (argc != 4) { - fprintf(stderr, "Incorrect number of arguments"); + if (argc != 5) { + fprintf(stderr, "Incorrect number of arguments\n"); return 1; } @@ -268,12 +309,15 @@ int main(int argc, char *argv[]) test_type = JUST_CRYPTO; } else if (strcmp(p, "-dso_ref") == 0) { test_type = DSO_REFTEST; + } else if (strcmp(p, "-no_atexit") == 0) { + test_type = NO_ATEXIT; } else { - fprintf(stderr, "Unrecognised argument"); + fprintf(stderr, "Unrecognised argument\n"); return 1; } path_crypto = argv[2]; path_ssl = argv[3]; + path_atexit = argv[4]; if (path_crypto == NULL || path_ssl == NULL) { fprintf(stderr, "Invalid libcrypto/libssl path\n"); return 1; -- 2.25.1