add a test for -fno-strict-aliasing

Change-Id: I0548968b062b813a4c546c4ddf79861875841210
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/79207
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bb01da1..a052367 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -122,7 +122,7 @@
 if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
   # Note clang-cl is odd and sets both CLANG and MSVC. We base our configuration
   # primarily on our normal Clang one.
-  set(C_CXX_FLAGS "-Werror -Wformat=2 -Wsign-compare -Wwrite-strings -Wvla -Wshadow -Wtype-limits -Wmissing-field-initializers")
+  set(C_CXX_FLAGS "-fno-strict-aliasing -Werror -Wformat=2 -Wsign-compare -Wwrite-strings -Wvla -Wshadow -Wtype-limits -Wmissing-field-initializers")
   if(MSVC)
     # clang-cl sets different default warnings than clang. It also treats -Wall
     # as -Weverything, to match MSVC. Instead -W3 is the alias for -Wall.
diff --git a/crypto/compiler_test.cc b/crypto/compiler_test.cc
index 95c3569..c65028f 100644
--- a/crypto/compiler_test.cc
+++ b/crypto/compiler_test.cc
@@ -21,6 +21,7 @@
 
 #include "test/test_util.h"
 
+namespace {
 
 // C and C++ have two forms of unspecified behavior: undefined behavior and
 // implementation-defined behavior.
@@ -215,3 +216,31 @@
   EXPECT_EQ(Bytes(bytes),
             Bytes(reinterpret_cast<uint8_t *>(&null), sizeof(null)));
 }
+
+static uintptr_t aba(uintptr_t *a, void **b) {
+  *a = (uintptr_t)1;
+  *b = NULL;
+  return *a;  // 0 if a == b, 1 if a and b are disjoint
+}
+
+TEST(CompilerTest, NoStrictAliasing) {
+  // Sequential memory access must be sequentially consistent across types.
+  // Compilers such as clang and gcc need to be passed -fno-strict-aliasing
+  // for this to remain true at at higher optimization levels. Use with the
+  // opposite configuration, -fstrict-aliasing, is not supported.
+  // Even though some subset of type punning through memory is considered
+  // undefined behavior, the subtlety of exactly which subset that is and the
+  // limited sanitizer-tooling support make it impractical to avoid reliably.
+  uint8_t aliased[sizeof(void *)] = {};
+  uint8_t zeros[sizeof(void *)] = {};
+
+  OPENSSL_memset(aliased, -1, sizeof(aliased));
+  EXPECT_EQ(aba((uintptr_t *)aliased, (void **)aliased), (uintptr_t)0);
+  EXPECT_EQ(Bytes(aliased), Bytes(zeros));
+
+  volatile auto volatile_aba = &aba;
+  OPENSSL_memset(aliased, -1, sizeof(aliased));
+  EXPECT_EQ(volatile_aba((uintptr_t *)aliased, (void **)aliased), (uintptr_t)0);
+  EXPECT_EQ(Bytes(aliased), Bytes(zeros));
+}
+}  // namespace