Add an option to statically link a custom libc++.

MSan and TSan both require instrumenting everything. Add some machinery so we
can do this on the bots.

Change-Id: I7d2106bc852ee976455d18787d3a20a35373a9e7
Reviewed-on: https://boringssl-review.googlesource.com/30644
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/.gitignore b/.gitignore
index bea7c55..db50b0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,8 @@
 util/bot/cmake-win32.zip
 util/bot/golang
 util/bot/gyp
+util/bot/libcxx
+util/bot/libcxxabi
 util/bot/libFuzzer
 util/bot/llvm-build
 util/bot/nasm-win32.exe
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fc7db08..7ba4a95 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,9 @@
   message(FATAL_ERROR "Could not find Go")
 endif()
 
+if (USE_CUSTOM_LIBCXX)
+  set(BORINGSSL_ALLOW_CXX_RUNTIME 1)
+endif()
 if (BORINGSSL_ALLOW_CXX_RUNTIME)
   add_definitions(-DBORINGSSL_ALLOW_CXX_RUNTIME)
 endif()
@@ -361,6 +364,61 @@
   set(ARCH "x86_64")
 endif()
 
+if (USE_CUSTOM_LIBCXX)
+  if (NOT CLANG)
+    message(FATAL_ERROR "USE_CUSTOM_LIBCXX only supported with Clang")
+  endif()
+
+  # CMAKE_CXX_FLAGS ends up in the linker flags as well, so use
+  # add_compile_options. There does not appear to be a way to set
+  # language-specific compile-only flags.
+  add_compile_options("-nostdinc++")
+  set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -nostdlib++")
+  include_directories(
+    SYSTEM
+    util/bot/libcxx/include
+    util/bot/libcxxabi/include
+  )
+
+  # This is patterned after buildtools/third_party/libc++/BUILD.gn and
+  # buildtools/third_party/libc++abi/BUILD.gn in Chromium.
+
+  file(GLOB LIBCXX_SOURCES "util/bot/libcxx/src/*.cpp")
+  file(GLOB LIBCXXABI_SOURCES "util/bot/libcxxabi/src/*.cpp")
+
+  # This file is meant for exception-less builds.
+  list(REMOVE_ITEM LIBCXXABI_SOURCES "trunk/src/cxa_noexception.cpp")
+  # libc++ also defines new and delete.
+  list(REMOVE_ITEM LIBCXXABI_SOURCES "trunk/src/stdlib_new_delete.cpp")
+  if (TSAN)
+    # ThreadSanitizer tries to intercept these symbols. Skip them to avoid
+    # symbol conflicts.
+    list(REMOVE_ITEM LIBCXXABI_SOURCES "trunk/src/cxa_guard.cpp")
+  endif()
+
+  add_library(libcxxabi ${LIBCXXABI_SOURCES})
+  target_compile_definitions(
+    libcxxabi PRIVATE
+    -D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS
+  )
+  set_target_properties(libcxxabi PROPERTIES COMPILE_FLAGS "-Wno-missing-prototypes -Wno-implicit-fallthrough")
+
+  add_library(libcxx ${LIBCXX_SOURCES})
+  if (ASAN OR MSAN OR TSAN)
+    # Sanitizers try to intercept new and delete.
+    target_compile_definitions(
+      libcxx PRIVATE
+      -D_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS
+    )
+  endif()
+  target_compile_definitions(
+    libcxx PRIVATE
+    -D_LIBCPP_BUILDING_LIBRARY
+    -DLIBCXX_BUILDING_LIBCXXABI
+  )
+  target_link_libraries(libcxx libcxxabi)
+endif()
+
 # Add minimal googletest targets. The provided one has many side-effects, and
 # googletest has a very straightforward build.
 add_library(boringssl_gtest third_party/googletest/src/gtest-all.cc)
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index 526fec8..d0a4d97 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -216,6 +216,12 @@
   target_link_libraries(crypto pthread)
 endif()
 
+# Every target depends on crypto, so we add libcxx as a dependency here to
+# simplify injecting it everywhere.
+if(USE_CUSTOM_LIBCXX)
+  target_link_libraries(crypto libcxx)
+endif()
+
 # TODO(davidben): Convert the remaining tests to GTest.
 add_executable(
   crypto_test
diff --git a/util/bot/DEPS b/util/bot/DEPS
index e622cb7..5dab203 100644
--- a/util/bot/DEPS
+++ b/util/bot/DEPS
@@ -19,6 +19,7 @@
   'checkout_fuzzer': False,
   'checkout_sde': False,
   'checkout_nasm': False,
+  'checkout_libcxx': False,
 }
 
 deps = {
@@ -39,6 +40,17 @@
     'url': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git' + '@' + '658ff786a213703ff0df6ba4a288e9a1e218c074',
     'condition': 'checkout_fuzzer',
   },
+
+  # Update the following revisions from
+  # https://chromium.googlesource.com/chromium/buildtools/+/master/DEPS
+  'boringssl/util/bot/libcxx': {
+    'url': Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' + '85a7702b4cc5d69402791fe685f151cf3076be71',
+    'condition': 'checkout_libcxx',
+  },
+  'boringssl/util/bot/libcxxabi': {
+    'url': Var('chromium_git') + '/chromium/llvm-project/libcxxabi.git' + '@' + '05a73941f3fb177c4a891d4ff2a4ed5785e3b80c',
+    'condition': 'checkout_libcxx',
+  },
 }
 
 recursedeps = [