Fix data <-> function pointer casts in thread_win.c.

The uses of |memcpy| to cast pointer-to-function to pointer-to-data and
back again did not have well-defined semantics. Use a union instead to
avoid the need for such a conversion get well-defined semantics.

Change-Id: I8ee54a83ba75440f7bc78c194eb55e2cf09b05d8
Reviewed-on: https://boringssl-review.googlesource.com/6972
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/thread_win.c b/crypto/thread_win.c
index e1b3a54..e48ab5f 100644
--- a/crypto/thread_win.c
+++ b/crypto/thread_win.c
@@ -31,7 +31,13 @@
 OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(CRITICAL_SECTION),
                        CRYPTO_MUTEX_too_small);
 
-static void run_once(CRYPTO_once_t *once, void (*init)(void *), void *arg) {
+union run_once_arg_t {
+  void (*func)(void);
+  void *data;
+};
+
+static void run_once(CRYPTO_once_t *once, void (*init)(union run_once_arg_t),
+                     union run_once_arg_t arg) {
   /* Values must be aligned. */
   assert((((uintptr_t) once) & 3) == 0);
 
@@ -72,17 +78,13 @@
   }
 }
 
-static void call_once_init(void *arg) {
-  void (*init_func)(void);
-  /* MSVC does not like casting between data and function pointers. */
-  memcpy(&init_func, &arg, sizeof(void *));
-  init_func();
+static void call_once_init(union run_once_arg_t arg) {
+  arg.func();
 }
 
 void CRYPTO_once(CRYPTO_once_t *in_once, void (*init)(void)) {
-  void *arg;
-  /* MSVC does not like casting between data and function pointers. */
-  memcpy(&arg, &init, sizeof(void *));
+  union run_once_arg_t arg;
+  arg.func = init;
   run_once(in_once, call_once_init, arg);
 }
 
@@ -109,16 +111,18 @@
   DeleteCriticalSection((CRITICAL_SECTION *) lock);
 }
 
-static void static_lock_init(void *arg) {
-  struct CRYPTO_STATIC_MUTEX *lock = arg;
+static void static_lock_init(union run_once_arg_t arg) {
+  struct CRYPTO_STATIC_MUTEX *lock = arg.data;
   if (!InitializeCriticalSectionAndSpinCount(&lock->lock, 0x400)) {
     abort();
   }
 }
 
 void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) {
+  union run_once_arg_t arg;
+  arg.data = lock;
   /* Since we have to support Windows XP, read locks are actually exclusive. */
-  run_once(&lock->once, static_lock_init, lock);
+  run_once(&lock->once, static_lock_init, arg);
   EnterCriticalSection(&lock->lock);
 }