diff options
author | Matt Caswell <matt@openssl.org> | 2018-11-20 16:32:55 +0100 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2019-01-04 14:19:39 +0100 |
commit | 660a1e0434eb5eb8548bea3ad35f3821d49c5c15 (patch) | |
tree | 5af256362cdd09642c877726e33fb1574a5f6c4f /include | |
parent | Fix shlibloadtest to properly execute the dso_ref test (diff) | |
download | openssl-660a1e0434eb5eb8548bea3ad35f3821d49c5c15.tar.xz openssl-660a1e0434eb5eb8548bea3ad35f3821d49c5c15.zip |
Fix a RUN_ONCE bug
We have a number of instances where there are multiple "init" functions for
a single CRYPTO_ONCE variable, e.g. to load config automatically or to not
load config automatically. Unfortunately the RUN_ONCE mechanism was not
correctly giving the right return value where an alternative init function
was being used.
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/7647)
Diffstat (limited to 'include')
-rw-r--r-- | include/internal/thread_once.h | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/include/internal/thread_once.h b/include/internal/thread_once.h index c7f0ab29e8..dcb0c689f3 100644 --- a/include/internal/thread_once.h +++ b/include/internal/thread_once.h @@ -9,6 +9,20 @@ #include <openssl/crypto.h> +/* + * DEFINE_RUN_ONCE: Define an initialiser function that should be run exactly + * once. It takes no arguments and returns and int result (1 for success or + * 0 for failure). Typical usage might be: + * + * DEFINE_RUN_ONCE(myinitfunc) + * { + * do_some_initialisation(); + * if (init_is_successful()) + * return 1; + * + * return 0; + * } + */ #define DEFINE_RUN_ONCE(init) \ static int init(void); \ int init##_ossl_ret_ = 0; \ @@ -17,10 +31,30 @@ init##_ossl_ret_ = init(); \ } \ static int init(void) + +/* + * DECLARE_RUN_ONCE: Declare an initialiser function that should be run exactly + * once that has been defined in another file via DEFINE_RUN_ONCE(). + */ #define DECLARE_RUN_ONCE(init) \ extern int init##_ossl_ret_; \ void init##_ossl_(void); +/* + * DEFINE_RUN_ONCE_STATIC: Define an initialiser function that should be run + * exactly once. This function will be declared as static within the file. It + * takes no arguments and returns and int result (1 for success or 0 for + * failure). Typical usage might be: + * + * DEFINE_RUN_ONCE_STATIC(myinitfunc) + * { + * do_some_initialisation(); + * if (init_is_successful()) + * return 1; + * + * return 0; + * } + */ #define DEFINE_RUN_ONCE_STATIC(init) \ static int init(void); \ static int init##_ossl_ret_ = 0; \ @@ -31,6 +65,46 @@ static int init(void) /* + * DEFINE_RUN_ONCE_STATIC_ALT: Define an alternative initialiser function. This + * function will be declared as static within the file. It takes no arguments + * and returns and int result (1 for success or 0 for failure). An alternative + * initialiser function is expected to be associated with a primary initialiser + * function defined via DEFINE_ONCE_STATIC where both functions use the same + * CRYPTO_ONCE object to synchronise. Where an alternative initialiser function + * is used only one of the primary or the alternative initialiser function will + * ever be called - and that function will be called exactly once. Definitition + * of an alternative initialiser function MUST occur AFTER the definition of the + * primiary initialiser function. + * + * Typical usage might be: + * + * DEFINE_RUN_ONCE_STATIC(myinitfunc) + * { + * do_some_initialisation(); + * if (init_is_successful()) + * return 1; + * + * return 0; + * } + * + * DEFINE_RUN_ONCE_STATIC_ALT(myaltinitfunc, myinitfunc) + * { + * do_some_alternative_initialisation(); + * if (init_is_successful()) + * return 1; + * + * return 0; + * } + */ +#define DEFINE_RUN_ONCE_STATIC_ALT(initalt, init) \ + static int initalt(void); \ + static void initalt##_ossl_(void) \ + { \ + init##_ossl_ret_ = initalt(); \ + } \ + static int initalt(void) + +/* * RUN_ONCE - use CRYPTO_THREAD_run_once, and check if the init succeeded * @once: pointer to static object of type CRYPTO_ONCE * @init: function name that was previously given to DEFINE_RUN_ONCE, @@ -43,3 +117,21 @@ */ #define RUN_ONCE(once, init) \ (CRYPTO_THREAD_run_once(once, init##_ossl_) ? init##_ossl_ret_ : 0) + +/* + * RUN_ONCE_ALT - use CRYPTO_THREAD_run_once, to run an alternative initialiser + * function and check if that initialisation succeeded + * @once: pointer to static object of type CRYPTO_ONCE + * @initalt: alternative initialiser function name that was previously given to + * DEFINE_RUN_ONCE_STATIC_ALT. This function must return 1 for + * success or 0 for failure. + * @init: primary initialiser function name that was previously given to + * DEFINE_RUN_ONCE_STATIC. This function must return 1 for success or + * 0 for failure. + * + * The return value is 1 on success (*) or 0 in case of error. + * + * (*) by convention, since the init function must return 1 on success. + */ +#define RUN_ONCE_ALT(once, initalt, init) \ + (CRYPTO_THREAD_run_once(once, initalt##_ossl_) ? init##_ossl_ret_ : 0) |