Automatically disable assembly with MSAN.

MSAN is incompatible with hand-written assembly code. Previously we
required that OPENSSL_NO_ASM be set when building with MSAN, and the
CMake build would take care of this. However, with other build systems
it wasn't always so easy.

This change automatically disables assembly when the compiler is
configured for MSAN.

Change-Id: I6c219120f62d16b99bafc2efb02948ecbecaf87f
Reviewed-on: https://boringssl-review.googlesource.com/31724
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fab1b3b..c614a65 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -274,7 +274,7 @@
 
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer")
-  set(OPENSSL_NO_ASM "1")
+  set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer")
 endif()
 
 if(ASAN)
@@ -284,7 +284,6 @@
 
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
-  set(OPENSSL_NO_ASM "1")
 endif()
 
 if(CFI)
diff --git a/crypto/crypto.c b/crypto/crypto.c
index 93e2f82..783d7d9 100644
--- a/crypto/crypto.c
+++ b/crypto/crypto.c
@@ -19,19 +19,6 @@
 #include "internal.h"
 
 
-#if defined(OPENSSL_MSAN) && !defined(OPENSSL_NO_ASM)
-// MSan works by instrumenting memory accesses in the compiler. Accesses from
-// uninstrumented code, such as assembly, are invisible to it. MSan will
-// incorrectly report reads from assembly-initialized memory as uninitialized.
-// If building BoringSSL with MSan, exclude assembly files from the build and
-// define OPENSSL_NO_ASM.
-//
-// This is checked here rather than in a header because the consumer might not
-// define OPENSSL_NO_ASM. It is only necessary for BoringSSL source files to be
-// built with it.
-#error "BoringSSL must be built with assembly disabled to use MSan."
-#endif
-
 #if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_STATIC_ARMCAP) && \
     (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
      defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \
diff --git a/crypto/curve25519/asm/x25519-asm-arm.S b/crypto/curve25519/asm/x25519-asm-arm.S
index 5a1cca4..905af07 100644
--- a/crypto/curve25519/asm/x25519-asm-arm.S
+++ b/crypto/curve25519/asm/x25519-asm-arm.S
@@ -17,6 +17,12 @@
  * domain licensed but the standard ISC license is included above to keep
  * licensing simple. */
 
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer) && !defined(OPENSSL_NO_ASM)
+#define OPENSSL_NO_ASM
+#endif
+#endif
+
 #if !defined(OPENSSL_NO_ASM) && defined(__arm__) && !defined(__APPLE__)
 
 #if defined(BORINGSSL_PREFIX)
diff --git a/crypto/perlasm/arm-xlate.pl b/crypto/perlasm/arm-xlate.pl
index a0adeb5..fffba80 100755
--- a/crypto/perlasm/arm-xlate.pl
+++ b/crypto/perlasm/arm-xlate.pl
@@ -130,6 +130,16 @@
     return $line;
 }
 
+print <<___;
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer) && !defined(OPENSSL_NO_ASM)
+#define OPENSSL_NO_ASM
+#endif
+#endif
+
+#if !defined(OPENSSL_NO_ASM)
+___
+
 print "#if defined(__arm__)\n" if ($flavour eq "linux32");
 print "#if defined(__aarch64__)\n" if ($flavour eq "linux64");
 
@@ -184,5 +194,6 @@
 }
 
 print "#endif\n" if ($flavour eq "linux32" || $flavour eq "linux64");
+print "#endif  // !OPENSSL_NO_ASM";
 
 close STDOUT;
diff --git a/crypto/perlasm/ppc-xlate.pl b/crypto/perlasm/ppc-xlate.pl
index de796d7..8013058 100644
--- a/crypto/perlasm/ppc-xlate.pl
+++ b/crypto/perlasm/ppc-xlate.pl
@@ -255,6 +255,16 @@
     "	.long	".sprintf "0x%X",(31<<26)|($rt<<21)|($l<<16)|(755<<1);
 };
 
+print <<___;
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer) && !defined(OPENSSL_NO_ASM)"
+#define OPENSSL_NO_ASM"
+#endif
+#endif
+
+#if !defined(OPENSSL_NO_ASM) && defined(__powerpc64__)
+___
+
 while($line=<>) {
 
     $line =~ s|[#!;].*$||;	# get rid of asm-style comments...
@@ -296,4 +306,6 @@
     print "\n";
 }
 
+print "#endif  // !OPENSSL_NO_ASM && __powerpc64__";
+
 close STDOUT;
diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl
index f6a57e0..3ec9b6c 100755
--- a/crypto/perlasm/x86_64-xlate.pl
+++ b/crypto/perlasm/x86_64-xlate.pl
@@ -1139,10 +1139,21 @@
 OPTION	DOTNAME
 ___
 }
-print STDOUT "#if defined(__x86_64__) && !defined(OPENSSL_NO_ASM)\n" if ($gas);
-print STDOUT "#if defined(BORINGSSL_PREFIX)\n" if ($gas);
-print STDOUT "#include <boringssl_prefix_symbols_asm.h>\n" if ($gas);
-print STDOUT "#endif\n" if ($gas);
+
+if ($gas) {
+	print <<___;
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer) && !defined(OPENSSL_NO_ASM)
+#define OPENSSL_NO_ASM
+#endif
+#endif
+
+#if defined(__x86_64__) && !defined(OPENSSL_NO_ASM)
+#if defined(BORINGSSL_PREFIX)
+#include <boringssl_prefix_symbols_asm.h>
+#endif
+___
+}
 
 while(defined(my $line=<>)) {
 
diff --git a/crypto/poly1305/poly1305_arm_asm.S b/crypto/poly1305/poly1305_arm_asm.S
index 06e7bd9..04f7c4c 100644
--- a/crypto/poly1305/poly1305_arm_asm.S
+++ b/crypto/poly1305/poly1305_arm_asm.S
@@ -1,3 +1,9 @@
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer) && !defined(OPENSSL_NO_ASM)
+#define OPENSSL_NO_ASM
+#endif
+#endif
+
 #if defined(__arm__) && !defined(OPENSSL_NO_ASM) && !defined(__APPLE__)
 
 #if defined(BORINGSSL_PREFIX)
diff --git a/include/openssl/base.h b/include/openssl/base.h
index f86968b..b68423e 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -231,9 +231,17 @@
 #endif
 #if __has_feature(memory_sanitizer)
 #define OPENSSL_MSAN
+#define OPENSSL_ASM_INCOMPATIBLE
 #endif
 #endif
 
+#if defined(OPENSSL_ASM_INCOMPATIBLE)
+#undef OPENSSL_ASM_INCOMPATIBLE
+#if !defined(OPENSSL_NO_ASM)
+#define OPENSSL_NO_ASM
+#endif
+#endif  // OPENSSL_ASM_INCOMPATIBLE
+
 // CRYPTO_THREADID is a dummy value.
 typedef int CRYPTO_THREADID;