You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

233 lines
5.9 KiB

  1. /* Copyright (c) 2015, Google Inc.
  2. *
  3. * Permission to use, copy, modify, and/or distribute this software for any
  4. * purpose with or without fee is hereby granted, provided that the above
  5. * copyright notice and this permission notice appear in all copies.
  6. *
  7. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. #include "internal.h"
  15. #include <openssl/crypto.h>
  16. #include <stdio.h>
  17. #if !defined(OPENSSL_NO_THREADS)
  18. #if defined(OPENSSL_WINDOWS)
  19. OPENSSL_MSVC_PRAGMA(warning(push, 3))
  20. #include <windows.h>
  21. OPENSSL_MSVC_PRAGMA(warning(pop))
  22. typedef HANDLE thread_t;
  23. static DWORD WINAPI thread_run(LPVOID arg) {
  24. void (*thread_func)(void);
  25. /* VC really doesn't like casting between data and function pointers. */
  26. OPENSSL_memcpy(&thread_func, &arg, sizeof(thread_func));
  27. thread_func();
  28. return 0;
  29. }
  30. static int run_thread(thread_t *out_thread, void (*thread_func)(void)) {
  31. void *arg;
  32. /* VC really doesn't like casting between data and function pointers. */
  33. OPENSSL_memcpy(&arg, &thread_func, sizeof(arg));
  34. *out_thread = CreateThread(NULL /* security attributes */,
  35. 0 /* default stack size */, thread_run, arg,
  36. 0 /* run immediately */, NULL /* ignore id */);
  37. return *out_thread != NULL;
  38. }
  39. static int wait_for_thread(thread_t thread) {
  40. return WaitForSingleObject(thread, INFINITE) == 0;
  41. }
  42. #else
  43. #include <pthread.h>
  44. #include <string.h>
  45. #include <time.h>
  46. typedef pthread_t thread_t;
  47. static void *thread_run(void *arg) {
  48. void (*thread_func)(void) = arg;
  49. thread_func();
  50. return NULL;
  51. }
  52. static int run_thread(thread_t *out_thread, void (*thread_func)(void)) {
  53. return pthread_create(out_thread, NULL /* default attributes */, thread_run,
  54. thread_func) == 0;
  55. }
  56. static int wait_for_thread(thread_t thread) {
  57. return pthread_join(thread, NULL) == 0;
  58. }
  59. #endif /* OPENSSL_WINDOWS */
  60. static unsigned g_once_init_called = 0;
  61. static void once_init(void) {
  62. g_once_init_called++;
  63. /* Sleep briefly so one |call_once_thread| instance will call |CRYPTO_once|
  64. * while the other is running this function. */
  65. #if defined(OPENSSL_WINDOWS)
  66. Sleep(1 /* milliseconds */);
  67. #else
  68. struct timespec req;
  69. OPENSSL_memset(&req, 0, sizeof(req));
  70. req.tv_nsec = 1000000;
  71. nanosleep(&req, NULL);
  72. #endif
  73. }
  74. static CRYPTO_once_t g_test_once = CRYPTO_ONCE_INIT;
  75. static void call_once_thread(void) {
  76. CRYPTO_once(&g_test_once, once_init);
  77. }
  78. static CRYPTO_once_t once_init_value = CRYPTO_ONCE_INIT;
  79. static CRYPTO_once_t once_bss;
  80. static int test_once(void) {
  81. if (g_once_init_called != 0) {
  82. fprintf(stderr, "g_once_init_called was non-zero at start.\n");
  83. return 0;
  84. }
  85. thread_t thread1, thread2;
  86. if (!run_thread(&thread1, call_once_thread) ||
  87. !run_thread(&thread2, call_once_thread) ||
  88. !wait_for_thread(thread1) ||
  89. !wait_for_thread(thread2)) {
  90. fprintf(stderr, "thread failed.\n");
  91. return 0;
  92. }
  93. CRYPTO_once(&g_test_once, once_init);
  94. if (g_once_init_called != 1) {
  95. fprintf(stderr, "Expected init function to be called once, but found %u.\n",
  96. g_once_init_called);
  97. return 0;
  98. }
  99. if (FIPS_mode()) {
  100. /* Our FIPS tooling currently requires that |CRYPTO_ONCE_INIT| is all
  101. * zeros, so the |CRYPTO_once_t| is placed in the bss. */
  102. if (OPENSSL_memcmp((void *)&once_init_value, (void *)&once_bss,
  103. sizeof(CRYPTO_once_t)) != 0) {
  104. fprintf(stderr, "CRYPTO_ONCE_INIT did not expand to all zeros.\n");
  105. return 0;
  106. }
  107. }
  108. return 1;
  109. }
  110. static int g_test_thread_ok = 0;
  111. static unsigned g_destructor_called_count = 0;
  112. static void thread_local_destructor(void *arg) {
  113. if (arg == NULL) {
  114. return;
  115. }
  116. unsigned *count = arg;
  117. (*count)++;
  118. }
  119. static void thread_local_test_thread(void) {
  120. void *ptr = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST);
  121. if (ptr != NULL) {
  122. return;
  123. }
  124. if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_TEST,
  125. &g_destructor_called_count,
  126. thread_local_destructor)) {
  127. return;
  128. }
  129. if (CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST) !=
  130. &g_destructor_called_count) {
  131. return;
  132. }
  133. g_test_thread_ok = 1;
  134. }
  135. static void thread_local_test2_thread(void) {}
  136. static int test_thread_local(void) {
  137. void *ptr = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST);
  138. if (ptr != NULL) {
  139. fprintf(stderr, "Thread-local data was non-NULL at start.\n");
  140. }
  141. thread_t thread;
  142. if (!run_thread(&thread, thread_local_test_thread) ||
  143. !wait_for_thread(thread)) {
  144. fprintf(stderr, "thread failed.\n");
  145. return 0;
  146. }
  147. if (!g_test_thread_ok) {
  148. fprintf(stderr, "Thread-local data didn't work in thread.\n");
  149. return 0;
  150. }
  151. if (g_destructor_called_count != 1) {
  152. fprintf(stderr,
  153. "Destructor should have been called once, but actually called %u "
  154. "times.\n",
  155. g_destructor_called_count);
  156. return 0;
  157. }
  158. /* thread_local_test2_thread doesn't do anything, but it tests that the
  159. * thread destructor function works even if thread-local storage wasn't used
  160. * for a thread. */
  161. if (!run_thread(&thread, thread_local_test2_thread) ||
  162. !wait_for_thread(thread)) {
  163. fprintf(stderr, "thread failed.\n");
  164. return 0;
  165. }
  166. return 1;
  167. }
  168. int main(int argc, char **argv) {
  169. if (!test_once() ||
  170. !test_thread_local()) {
  171. return 1;
  172. }
  173. printf("PASS\n");
  174. return 0;
  175. }
  176. #else /* OPENSSL_NO_THREADS */
  177. int main(int argc, char **argv) {
  178. printf("PASS\n");
  179. return 0;
  180. }
  181. #endif