[llvm-branch-commits] [compiler-rt] 697a0d1 - Update libraries from emscripten repo

Sam Clegg via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat May 22 06:57:47 PDT 2021


Author: Sam Clegg
Date: 2021-05-22T06:39:33-07:00
New Revision: 697a0d1925cf37442b444d6b3eee6fe047d7e5bc

URL: https://github.com/llvm/llvm-project/commit/697a0d1925cf37442b444d6b3eee6fe047d7e5bc
DIFF: https://github.com/llvm/llvm-project/commit/697a0d1925cf37442b444d6b3eee6fe047d7e5bc.diff

LOG: Update libraries from emscripten repo

These changes are from emscripten as of 3ad991a6cc3c085ac325be.

Added: 
    

Modified: 
    compiler-rt/include/sanitizer/tsan_interface_atomic.h
    compiler-rt/lib/asan/asan_errors.cpp
    compiler-rt/lib/asan/asan_flags.cpp
    compiler-rt/lib/asan/asan_interceptors.cpp
    compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
    compiler-rt/lib/asan/asan_malloc_linux.cpp
    compiler-rt/lib/asan/asan_mapping.h
    compiler-rt/lib/asan/asan_poisoning.cpp
    compiler-rt/lib/asan/asan_poisoning.h
    compiler-rt/lib/asan/asan_posix.cpp
    compiler-rt/lib/asan/asan_rtl.cpp
    compiler-rt/lib/asan/asan_shadow_setup.cpp
    compiler-rt/lib/asan/asan_thread.cpp
    compiler-rt/lib/builtins/powitf2.c
    compiler-rt/lib/interception/interception.h
    compiler-rt/lib/interception/interception_linux.h
    compiler-rt/lib/lsan/lsan.cpp
    compiler-rt/lib/lsan/lsan_allocator.cpp
    compiler-rt/lib/lsan/lsan_allocator.h
    compiler-rt/lib/lsan/lsan_common.cpp
    compiler-rt/lib/lsan/lsan_common.h
    compiler-rt/lib/lsan/lsan_common_linux.cpp
    compiler-rt/lib/lsan/lsan_interceptors.cpp
    compiler-rt/lib/lsan/lsan_linux.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
    compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
    compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_linux.h
    compiler-rt/lib/sanitizer_common/sanitizer_platform.h
    compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
    compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
    compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
    compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
    compiler-rt/lib/ubsan/ubsan_checks.inc
    compiler-rt/lib/ubsan/ubsan_diag.cpp
    compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp
    compiler-rt/lib/ubsan/ubsan_flags.cpp
    compiler-rt/lib/ubsan/ubsan_handlers.cpp
    compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp
    compiler-rt/lib/ubsan/ubsan_init.cpp
    compiler-rt/lib/ubsan/ubsan_init_standalone.cpp
    compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp
    compiler-rt/lib/ubsan/ubsan_monitor.cpp
    compiler-rt/lib/ubsan/ubsan_platform.h
    compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
    compiler-rt/lib/ubsan/ubsan_type_hash.cpp
    compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp
    compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp
    compiler-rt/lib/ubsan/ubsan_value.cpp
    compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp
    compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
    compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp
    libcxx/include/__config
    libcxx/include/__sso_allocator
    libcxx/include/codecvt
    libcxx/include/ios
    libcxx/include/memory
    libcxx/include/regex
    libcxx/include/typeinfo
    libcxx/src/include/config_elast.h
    libcxx/src/ios.cpp
    libcxx/src/iostream.cpp
    libcxx/src/new.cpp
    libcxx/src/regex.cpp
    libcxxabi/include/cxxabi.h
    libcxxabi/src/abort_message.cpp
    libcxxabi/src/cxa_default_handlers.cpp
    libcxxabi/src/cxa_exception.cpp
    libcxxabi/src/cxa_exception.h
    libcxxabi/src/cxa_handlers.cpp
    libcxxabi/src/cxa_personality.cpp
    libcxxabi/src/private_typeinfo.cpp
    libcxxabi/src/stdlib_new_delete.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/include/sanitizer/tsan_interface_atomic.h b/compiler-rt/include/sanitizer/tsan_interface_atomic.h
index 8052bc1d56b38..5e41e2256c300 100644
--- a/compiler-rt/include/sanitizer/tsan_interface_atomic.h
+++ b/compiler-rt/include/sanitizer/tsan_interface_atomic.h
@@ -30,7 +30,7 @@ __extension__ typedef __int128 __tsan_atomic128;
 #endif
 
 // Part of ABI, do not change.
-// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
+// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
 typedef enum {
   __tsan_memory_order_relaxed,
   __tsan_memory_order_consume,

diff  --git a/compiler-rt/lib/asan/asan_errors.cpp b/compiler-rt/lib/asan/asan_errors.cpp
index 541c6e0353b57..e1c953b141643 100644
--- a/compiler-rt/lib/asan/asan_errors.cpp
+++ b/compiler-rt/lib/asan/asan_errors.cpp
@@ -480,6 +480,17 @@ ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr,
       scariness.Scare(bug_type_score + read_after_free_bonus, bug_descr);
       if (far_from_bounds) scariness.Scare(10, "far-from-bounds");
     }
+#if SANITIZER_EMSCRIPTEN
+    // If address is in the first page (64 KB), then it is likely that the
+    // access is a result of a null pointer dereference.
+    else if (addr < 65536) {
+      bug_descr = "null-pointer-dereference";
+      scariness.Scare(25, bug_descr);
+    } else if (AddrIsInShadow(addr)) {
+      bug_descr = "shadow-access";
+      scariness.Scare(25, bug_descr);
+    }
+#endif
   }
 }
 

diff  --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp
index c5c70eaed737f..a09535f8269e0 100644
--- a/compiler-rt/lib/asan/asan_flags.cpp
+++ b/compiler-rt/lib/asan/asan_flags.cpp
@@ -22,6 +22,12 @@
 #include "ubsan/ubsan_flags.h"
 #include "ubsan/ubsan_platform.h"
 
+#if SANITIZER_EMSCRIPTEN
+extern "C" void emscripten_builtin_free(void *);
+#include <emscripten/em_asm.h>
+#endif
+
+
 namespace __asan {
 
 Flags asan_flags_dont_use_directly;  // use via flags().
@@ -58,7 +64,11 @@ void InitializeFlags() {
     CommonFlags cf;
     cf.CopyFrom(*common_flags());
     cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS;
+#if !SANITIZER_EMSCRIPTEN
+    // getenv on emscripten uses malloc, which we can't when using LSan.
+    // You can't run external symbolizer executables anyway.
     cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
+#endif
     cf.malloc_context_size = kDefaultMallocContextSize;
     cf.intercept_tls_get_addr = true;
     cf.exitcode = 1;
@@ -119,6 +129,26 @@ void InitializeFlags() {
   lsan_parser.ParseString(lsan_default_options);
 #endif
 
+#if SANITIZER_EMSCRIPTEN
+  char *options;
+  // Override from Emscripten Module.
+#define MAKE_OPTION_LOAD(parser, name) \
+    options = (char*) EM_ASM_INT({ \
+      return withBuiltinMalloc(function () { \
+        return allocateUTF8(Module[name] || 0); \
+      }); \
+    }); \
+    parser.ParseString(options); \
+    emscripten_builtin_free(options);
+
+  MAKE_OPTION_LOAD(asan_parser, 'ASAN_OPTIONS');
+#if CAN_SANITIZE_LEAKS
+  MAKE_OPTION_LOAD(lsan_parser, 'LSAN_OPTIONS');
+#endif
+#if CAN_SANITIZE_UB
+  MAKE_OPTION_LOAD(ubsan_parser, 'UBSAN_OPTIONS');
+#endif
+#else
   // Override from command line.
   asan_parser.ParseStringFromEnv("ASAN_OPTIONS");
 #if CAN_SANITIZE_LEAKS
@@ -127,12 +157,18 @@ void InitializeFlags() {
 #if CAN_SANITIZE_UB
   ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS");
 #endif
+#endif // SANITIZER_EMSCRIPTEN
 
   InitializeCommonFlags();
 
   // TODO(eugenis): dump all flags at verbosity>=2?
   if (Verbosity()) ReportUnrecognizedFlags();
 
+#if SANITIZER_EMSCRIPTEN
+  if (common_flags()->malloc_context_size <= 1)
+    StackTrace::snapshot_stack = false;
+#endif // SANITIZER_EMSCRIPTEN
+
   if (common_flags()->help) {
     // TODO(samsonov): print all of the flags (ASan, LSan, common).
     asan_parser.PrintFlagDescriptions();

diff  --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp
index b19cf25c7cd00..9002c7fe4dbd9 100644
--- a/compiler-rt/lib/asan/asan_interceptors.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors.cpp
@@ -23,10 +23,10 @@
 #include "lsan/lsan_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
-// There is no general interception at all on Fuchsia and RTEMS.
-// Only the functions in asan_interceptors_memintrinsics.cpp are
+// There is no general interception at all on Fuchsia, RTEMS and Emscripten.
+// Only the functions in asan_interceptors_memintrinsics.cc are
 // really defined to replace libc functions.
-#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
+#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN
 
 #if SANITIZER_POSIX
 #include "sanitizer_common/sanitizer_posix.h"
@@ -719,4 +719,4 @@ void InitializeAsanInterceptors() {
 
 } // namespace __asan
 
-#endif  // !SANITIZER_FUCHSIA
+#endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN

diff  --git a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
index ccdd5159042cf..7280523b86b70 100644
--- a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
@@ -30,7 +30,7 @@ void *__asan_memmove(void *to, const void *from, uptr size) {
   ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
 }
 
-#if SANITIZER_FUCHSIA || SANITIZER_RTEMS
+#if SANITIZER_FUCHSIA || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN
 
 // Fuchsia and RTEMS don't use sanitizer_common_interceptors.inc, but
 // the only things there it wants are these three.  Just define them
@@ -40,4 +40,4 @@ extern "C" decltype(__asan_memcpy) memcpy[[gnu::alias("__asan_memcpy")]];
 extern "C" decltype(__asan_memmove) memmove[[gnu::alias("__asan_memmove")]];
 extern "C" decltype(__asan_memset) memset[[gnu::alias("__asan_memset")]];
 
-#endif  // SANITIZER_FUCHSIA || SANITIZER_RTEMS
+#endif  // SANITIZER_FUCHSIA || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN

diff  --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp
index faa8968a5d009..20719cd51f959 100644
--- a/compiler-rt/lib/asan/asan_malloc_linux.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp
@@ -15,7 +15,8 @@
 
 #include "sanitizer_common/sanitizer_platform.h"
 #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
-    SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS
+    SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS || \
+    SANITIZER_EMSCRIPTEN
 
 #include "sanitizer_common/sanitizer_allocator_checks.h"
 #include "sanitizer_common/sanitizer_errno.h"

diff  --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h
index 41fb49ee46d46..67c5448729a3d 100644
--- a/compiler-rt/lib/asan/asan_mapping.h
+++ b/compiler-rt/lib/asan/asan_mapping.h
@@ -268,8 +268,8 @@ extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;  // Initialized in __asan_init.
 
 #if SANITIZER_MYRIAD2
 #include "asan_mapping_myriad.h"
-#elif defined(__sparc__) && SANITIZER_WORDSIZE == 64
-#include "asan_mapping_sparc64.h"
+#elif SANITIZER_EMSCRIPTEN
+#include "asan_mapping_emscripten.h"
 #else
 #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
 

diff  --git a/compiler-rt/lib/asan/asan_poisoning.cpp b/compiler-rt/lib/asan/asan_poisoning.cpp
index f3fbe684e2cbc..a3152eab85409 100644
--- a/compiler-rt/lib/asan/asan_poisoning.cpp
+++ b/compiler-rt/lib/asan/asan_poisoning.cpp
@@ -65,7 +65,9 @@ struct ShadowSegmentEndpoint {
 void FlushUnneededASanShadowMemory(uptr p, uptr size) {
   // Since asan's mapping is compacting, the shadow chunk may be
   // not page-aligned, so we only flush the page-aligned portion.
+#if !SANITIZER_EMSCRIPTEN
   ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
+#endif
 }
 
 void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
@@ -187,6 +189,15 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
     if (!AddrIsInMem(beg) && !AddrIsInShadow(beg)) return 0;
     if (!AddrIsInMem(end) && !AddrIsInShadow(end)) return 0;
   } else {
+#if SANITIZER_EMSCRIPTEN
+    // XXX Emscripten hack XXX
+    // Null pointer handling, since Emscripten does not crash on null pointer,
+    // ASan must catch null pointer dereference by itself.
+    // Unfortunately, this function returns 0 to mean the region is not
+    // poisoned, so we must return 1 instead if we receive a region
+    // starting at 0.
+    if (!beg) return 1;
+#endif
     if (!AddrIsInMem(beg)) return beg;
     if (!AddrIsInMem(end)) return end;
   }

diff  --git a/compiler-rt/lib/asan/asan_poisoning.h b/compiler-rt/lib/asan/asan_poisoning.h
index 62dd9bd0edd32..0c8c283986a62 100644
--- a/compiler-rt/lib/asan/asan_poisoning.h
+++ b/compiler-rt/lib/asan/asan_poisoning.h
@@ -54,6 +54,10 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
       // RTEMS doesn't have have pages, let alone a fast way to zero
       // them, so default to memset.
       SANITIZER_RTEMS == 1 ||
+      // Emscripten doesn't have a nice way to zero whole pages.
+      // The bulk memory proposal will allow memset to be optimized, but
+      // even then, we still must use memset.
+      SANITIZER_EMSCRIPTEN == 1 ||
       shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
     REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
   } else {

diff  --git a/compiler-rt/lib/asan/asan_posix.cpp b/compiler-rt/lib/asan/asan_posix.cpp
index 920d216624a3f..85ebd181ebf2f 100644
--- a/compiler-rt/lib/asan/asan_posix.cpp
+++ b/compiler-rt/lib/asan/asan_posix.cpp
@@ -83,7 +83,7 @@ void PlatformTSDDtor(void *tsd) {
   atomic_signal_fence(memory_order_seq_cst);
   AsanThread::TSDDtor(tsd);
 }
-#else
+#elif !SANITIZER_EMSCRIPTEN
 static pthread_key_t tsd_key;
 static bool tsd_key_inited = false;
 void AsanTSDInit(void (*destructor)(void *tsd)) {

diff  --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp
index 594d7752eea62..5665654e942fb 100644
--- a/compiler-rt/lib/asan/asan_rtl.cpp
+++ b/compiler-rt/lib/asan/asan_rtl.cpp
@@ -50,6 +50,7 @@ static void AsanDie() {
     Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
     SleepForSeconds(flags()->sleep_before_dying);
   }
+#if !SANITIZER_EMSCRIPTEN
   if (flags()->unmap_shadow_on_exit) {
     if (kMidMemBeg) {
       UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
@@ -59,6 +60,7 @@ static void AsanDie() {
         UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
     }
   }
+#endif
 }
 
 static void AsanCheckFailed(const char *file, int line, const char *cond,
@@ -314,7 +316,7 @@ static void asan_atexit() {
 }
 
 static void InitializeHighMemEnd() {
-#if !SANITIZER_MYRIAD2
+#if !SANITIZER_MYRIAD2 && !SANITIZER_EMSCRIPTEN
 #if !ASAN_FIXED_MAPPING
   kHighMemEnd = GetMaxUserVirtualAddress();
   // Increase kHighMemEnd to make sure it's properly
@@ -463,7 +465,9 @@ static void AsanInitInternal() {
   InitializeShadowMemory();
 
   AsanTSDInit(PlatformTSDDtor);
+#if !SANITIZER_EMSCRIPTEN
   InstallDeadlySignalHandlers(AsanOnDeadlySignal);
+#endif
 
   AllocatorOptions allocator_options;
   allocator_options.SetFrom(flags(), common_flags());

diff  --git a/compiler-rt/lib/asan/asan_shadow_setup.cpp b/compiler-rt/lib/asan/asan_shadow_setup.cpp
index 17324932a86f9..e17da6a3696a9 100644
--- a/compiler-rt/lib/asan/asan_shadow_setup.cpp
+++ b/compiler-rt/lib/asan/asan_shadow_setup.cpp
@@ -13,9 +13,9 @@
 
 #include "sanitizer_common/sanitizer_platform.h"
 
-// asan_fuchsia.cpp and asan_rtems.cpp have their own
+// asan_fuchsia.cc, asan_rtems.cc and asan_emscripten.cc have their own
 // InitializeShadowMemory implementation.
-#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
+#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN
 
 #include "asan_internal.h"
 #include "asan_mapping.h"

diff  --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index 6734d9a1668c7..b573b7f2817b1 100644
--- a/compiler-rt/lib/asan/asan_thread.cpp
+++ b/compiler-rt/lib/asan/asan_thread.cpp
@@ -101,7 +101,9 @@ void AsanThread::Destroy() {
   VReport(1, "T%d exited\n", tid);
 
   malloc_storage().CommitBack();
+#if !SANITIZER_EMSCRIPTEN
   if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
+#endif
   asanThreadRegistry().FinishThread(tid);
   FlushToDeadThreadStats(&stats_);
   // We also clear the shadow on thread destruction because
@@ -249,7 +251,9 @@ thread_return_t AsanThread::ThreadStart(
   if (signal_thread_is_registered)
     atomic_store(signal_thread_is_registered, 1, memory_order_release);
 
+#if !SANITIZER_EMSCRIPTEN
   if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
+#endif
 
   if (!start_routine_) {
     // start_routine_ == 0 if we're on the main thread or on one of the

diff  --git a/compiler-rt/lib/builtins/powitf2.c b/compiler-rt/lib/builtins/powitf2.c
index fcbdb4c2ee2a6..443da04b29b19 100644
--- a/compiler-rt/lib/builtins/powitf2.c
+++ b/compiler-rt/lib/builtins/powitf2.c
@@ -12,7 +12,7 @@
 
 #include "int_lib.h"
 
-#if _ARCH_PPC
+#if defined _ARCH_PPC || defined __wasm__
 
 // Returns: a ^ b
 

diff  --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h
index d27a8ccf92a8e..aa2986b1c92fa 100644
--- a/compiler-rt/lib/interception/interception.h
+++ b/compiler-rt/lib/interception/interception.h
@@ -18,7 +18,8 @@
 
 #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \
     !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_WINDOWS && \
-    !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS
+    !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS && \
+    !SANITIZER_EMSCRIPTEN
 # error "Interception doesn't work on this operating system."
 #endif
 
@@ -130,7 +131,7 @@ const interpose_substitution substitution_##func_name[] \
     extern "C" ret_type func(__VA_ARGS__);
 # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
     extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
-#elif SANITIZER_RTEMS
+#elif SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN
 # define WRAP(x) x
 # define WRAPPER_NAME(x) #x
 # define INTERCEPTOR_ATTRIBUTE
@@ -162,6 +163,13 @@ const interpose_substitution substitution_##func_name[] \
 # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
 # define REAL(x) __unsanitized_##x
 # define DECLARE_REAL(ret_type, func, ...)
+#elif SANITIZER_EMSCRIPTEN
+// Sanitizer runtimes on Emscripten just define functions directly to override
+// the libc functions. If the real version is really needed, they can be defined
+// with the emscripten_builtin_ prefix.
+# define REAL(x) emscripten_builtin_##x
+# define DECLARE_REAL(ret_type, func, ...) \
+    extern "C" ret_type REAL(func)(__VA_ARGS__);
 #elif SANITIZER_RTEMS
 # define REAL(x) __real_ ## x
 # define DECLARE_REAL(ret_type, func, ...) \
@@ -202,7 +210,8 @@ const interpose_substitution substitution_##func_name[] \
 // macros does its job. In exceptional cases you may need to call REAL(foo)
 // without defining INTERCEPTOR(..., foo, ...). For example, if you override
 // foo with an interceptor for other function.
-#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
+#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && \
+    !SANITIZER_EMSCRIPTEN
 # define DEFINE_REAL(ret_type, func, ...) \
     typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
     namespace __interception { \
@@ -272,16 +281,16 @@ const interpose_substitution substitution_##func_name[] \
 // INTERCEPT_FUNCTION macro, only its name.
 namespace __interception {
 #if defined(_WIN64)
-typedef unsigned long long uptr;
+typedef unsigned long long uptr;  // NOLINT
 #else
-typedef unsigned long uptr;
+typedef unsigned long uptr;  // NOLINT
 #endif  // _WIN64
 }  // namespace __interception
 
 #define INCLUDED_FROM_INTERCEPTION_LIB
 
 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS
+    SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 
 # include "interception_linux.h"
 # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)

diff  --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h
index e578da0cf64ee..5a98b57d01d7b 100644
--- a/compiler-rt/lib/interception/interception_linux.h
+++ b/compiler-rt/lib/interception/interception_linux.h
@@ -12,7 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS
+    SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 
 #if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
 # error "interception_linux.h should be included from interception library only"
@@ -35,8 +35,9 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
       (::__interception::uptr) & (func),          \
       (::__interception::uptr) & WRAP(func))
 
-// Android,  Solaris and OpenBSD do not have dlvsym
-#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD
+// Android,  Solaris, OpenBSD and emscripten do not have dlvsym
+#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD && \
+    !SANITIZER_EMSCRIPTEN
 #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
   ::__interception::InterceptFunction(                        \
       #func, symver,                                          \

diff  --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp
index 4ce03046ffb7f..8e3f0294eea04 100644
--- a/compiler-rt/lib/lsan/lsan.cpp
+++ b/compiler-rt/lib/lsan/lsan.cpp
@@ -20,6 +20,11 @@
 #include "lsan_common.h"
 #include "lsan_thread.h"
 
+#if SANITIZER_EMSCRIPTEN
+extern "C" void emscripten_builtin_free(void *);
+#include <emscripten/em_asm.h>
+#endif
+
 bool lsan_inited;
 bool lsan_init_is_running;
 
@@ -58,7 +63,11 @@ static void InitializeFlags() {
   {
     CommonFlags cf;
     cf.CopyFrom(*common_flags());
+#if !SANITIZER_EMSCRIPTEN
+    // getenv on emscripten uses malloc, which we can't when using LSan.
+    // You can't run external symbolizers anyway.
     cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
+#endif
     cf.malloc_context_size = 30;
     cf.intercept_tls_get_addr = true;
     cf.detect_leaks = true;
@@ -76,7 +85,22 @@ static void InitializeFlags() {
   // Override from user-specified string.
   const char *lsan_default_options = MaybeCallLsanDefaultOptions();
   parser.ParseString(lsan_default_options);
-  parser.ParseStringFromEnv("LSAN_OPTIONS");
+#if SANITIZER_EMSCRIPTEN
+  char *options = (char*) EM_ASM_INT({
+    return withBuiltinMalloc(function () {
+      return allocateUTF8(Module['LSAN_OPTIONS'] || 0);
+    });
+  });
+  parser.ParseString(options);
+  emscripten_builtin_free(options);
+#else
+  parser.ParseString(GetEnv("LSAN_OPTIONS"));
+#endif // SANITIZER_EMSCRIPTEN
+
+#if SANITIZER_EMSCRIPTEN
+  if (common_flags()->malloc_context_size <= 1)
+    StackTrace::snapshot_stack = false;
+#endif // SANITIZER_EMSCRIPTEN
 
   SetVerbosity(common_flags()->verbosity);
 
@@ -113,7 +137,10 @@ extern "C" void __lsan_init() {
   InitTlsSize();
   InitializeInterceptors();
   InitializeThreadRegistry();
+#if !SANITIZER_EMSCRIPTEN
+  // Emscripten does not have signals
   InstallDeadlySignalHandlers(LsanOnDeadlySignal);
+#endif
   u32 tid = ThreadCreate(0, 0, true);
   CHECK_EQ(tid, 0);
   ThreadStart(tid, GetTid());

diff  --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp
index d86c3921395cb..845526a8771a1 100644
--- a/compiler-rt/lib/lsan/lsan_allocator.cpp
+++ b/compiler-rt/lib/lsan/lsan_allocator.cpp
@@ -26,7 +26,7 @@
 extern "C" void *memset(void *ptr, int value, uptr num);
 
 namespace __lsan {
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__wasm32__)
 static const uptr kMaxAllowedMallocSize = 1UL << 30;
 #elif defined(__mips64) || defined(__aarch64__)
 static const uptr kMaxAllowedMallocSize = 4UL << 30;

diff  --git a/compiler-rt/lib/lsan/lsan_allocator.h b/compiler-rt/lib/lsan/lsan_allocator.h
index e139709976728..3df5f77bd3bcf 100644
--- a/compiler-rt/lib/lsan/lsan_allocator.h
+++ b/compiler-rt/lib/lsan/lsan_allocator.h
@@ -50,15 +50,22 @@ struct ChunkMetadata {
 };
 
 #if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
-    defined(__arm__)
+    defined(__arm__) || defined(__wasm32__)
+static const uptr kRegionSizeLog = 20;
+static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+template <typename AddressSpaceView>
+using ByteMapASVT =
+    TwoLevelByteMap<(kNumRegions >> 12), 1 << 12, AddressSpaceView>;
+
 template <typename AddressSpaceViewTy>
 struct AP32 {
   static const uptr kSpaceBeg = 0;
   static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
   static const uptr kMetadataSize = sizeof(ChunkMetadata);
   typedef __sanitizer::CompactSizeClassMap SizeClassMap;
-  static const uptr kRegionSizeLog = 20;
+  static const uptr kRegionSizeLog = __lsan::kRegionSizeLog;
   using AddressSpaceView = AddressSpaceViewTy;
+  using ByteMap = __lsan::ByteMapASVT<AddressSpaceView>;
   typedef NoOpMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };

diff  --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp
index 9ff9f4c5d1c97..fdd53733241b5 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -1,4 +1,4 @@
-//=-- lsan_common.cpp -----------------------------------------------------===//
+//=-- lsan_common.cc ------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -25,6 +25,10 @@
 #include "sanitizer_common/sanitizer_thread_registry.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
 
+#if SANITIZER_EMSCRIPTEN
+#include "lsan/lsan_allocator.h"
+#endif
+
 #if CAN_SANITIZE_LEAKS
 namespace __lsan {
 
@@ -84,7 +88,7 @@ static const char kStdSuppressions[] =
 
 void InitializeSuppressions() {
   CHECK_EQ(nullptr, suppression_ctx);
-  suppression_ctx = new (suppression_placeholder)
+  suppression_ctx = new (suppression_placeholder) // NOLINT
       SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
   suppression_ctx->ParseFromFile(flags()->suppressions);
   if (&__lsan_default_suppressions)
@@ -162,7 +166,16 @@ void ScanRangeForPointers(uptr begin, uptr end,
   uptr pp = begin;
   if (pp % alignment)
     pp = pp + alignment - pp % alignment;
-  for (; pp + sizeof(void *) <= end; pp += alignment) {
+
+  // Emscripten in non-threaded mode stores thread_local variables in the
+  // same place as normal globals. This means allocator_cache must be skipped
+  // when scanning globals instead of when scanning thread-locals.
+#if SANITIZER_EMSCRIPTEN && !defined(__EMSCRIPTEN_PTHREADS__)
+  uptr cache_begin, cache_end;
+  GetAllocatorCacheRange(&cache_begin, &cache_end);
+#endif
+
+  for (; pp + sizeof(void *) <= end; pp += alignment) {  // NOLINT
     void *p = *reinterpret_cast<void **>(pp);
     if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
     uptr chunk = PointsIntoChunk(p);
@@ -181,6 +194,14 @@ void ScanRangeForPointers(uptr begin, uptr end,
       continue;
     }
 
+#if SANITIZER_EMSCRIPTEN && !defined(__EMSCRIPTEN_PTHREADS__)
+    if (cache_begin <= pp && pp < cache_end) {
+      LOG_POINTERS("%p: skipping because it overlaps the cache %p-%p.\n",
+          pp, cache_begin, cache_end);
+      continue;
+    }
+#endif
+
     m.set_tag(tag);
     LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p,
                  chunk, chunk + m.requested_size(), m.requested_size());
@@ -211,9 +232,10 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
   ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
 }
 
+#if !SANITIZER_EMSCRIPTEN
 // Scans thread data (stacks and TLS) for heap pointers.
-static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
-                           Frontier *frontier) {
+void ProcessThreads(SuspendedThreadsList const &suspended_threads,
+                    Frontier *frontier) {
   InternalMmapVector<uptr> registers(suspended_threads.RegisterCount());
   uptr registers_begin = reinterpret_cast<uptr>(registers.data());
   uptr registers_end =
@@ -307,6 +329,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
     }
   }
 }
+#endif // !SANITIZER_EMSCRIPTEN
 
 void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
                     uptr region_begin, uptr region_end, bool is_readable) {
@@ -322,14 +345,22 @@ void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
                          kReachable);
 }
 
+#if SANITIZER_EMSCRIPTEN
+extern "C" uptr emscripten_get_heap_size();
+#endif
+
 static void ProcessRootRegion(Frontier *frontier,
                               const RootRegion &root_region) {
+#if SANITIZER_EMSCRIPTEN
+  ScanRootRegion(frontier, root_region, 0, emscripten_get_heap_size(), true);
+#else
   MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
   MemoryMappedSegment segment;
   while (proc_maps.Next(&segment)) {
     ScanRootRegion(frontier, root_region, segment.start, segment.end,
                    segment.IsReadable());
   }
+#endif // SANITIZER_EMSCRIPTEN
 }
 
 // Scans root regions for heap pointers.
@@ -433,6 +464,7 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) {
 // On all other platforms, this simply checks to ensure that the caller pc is
 // valid before reporting chunks as leaked.
 void ProcessPC(Frontier *frontier) {
+#if !SANITIZER_EMSCRIPTEN
   StackDepotReverseMap stack_depot_reverse_map;
   InvalidPCParam arg;
   arg.frontier = frontier;
@@ -440,6 +472,7 @@ void ProcessPC(Frontier *frontier) {
   arg.skip_linker_allocations =
       flags()->use_tls && flags()->use_ld_allocations && GetLinker() != nullptr;
   ForEachChunk(MarkInvalidPCCb, &arg);
+#endif
 }
 
 // Sets the appropriate tag on each chunk.
@@ -555,7 +588,9 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
   CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
   CHECK(param);
   CHECK(!param->success);
+#if !SANITIZER_EMSCRIPTEN
   ReportUnsuspendedThreads(suspended_threads);
+#endif
   ClassifyAllChunks(suspended_threads);
   ForEachChunk(CollectLeaksCb, &param->leak_report);
   // Clean up for subsequent leak checks. This assumes we did not overwrite any
@@ -647,8 +682,15 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
 static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
   StackTrace stack = StackDepotGet(stack_trace_id);
   for (uptr i = 0; i < stack.size; i++) {
+#if SANITIZER_EMSCRIPTEN
+    // On Emscripten, the stack trace is the actual call site, not
+    // the code that would be executed after the return.
+    // Therefore, StackTrace::GetPreviousInstructionPc is not needed.
+    Suppression *s = GetSuppressionForAddr(stack.trace[i]);
+#else
     Suppression *s = GetSuppressionForAddr(
         StackTrace::GetPreviousInstructionPc(stack.trace[i]));
+#endif
     if (s) return s;
   }
   return nullptr;

diff  --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h
index d24abe31b71b5..6901e18829aeb 100644
--- a/compiler-rt/lib/lsan/lsan_common.h
+++ b/compiler-rt/lib/lsan/lsan_common.h
@@ -40,7 +40,7 @@
 #elif defined(__arm__) && \
     SANITIZER_LINUX && !SANITIZER_ANDROID
 #define CAN_SANITIZE_LEAKS 1
-#elif SANITIZER_NETBSD
+#elif SANITIZER_EMSCRIPTEN
 #define CAN_SANITIZE_LEAKS 1
 #else
 #define CAN_SANITIZE_LEAKS 0
@@ -213,6 +213,10 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
                            uptr *cache_end, DTLS **dtls);
 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
                             void *arg);
+// Scans thread data (stacks and TLS) for heap pointers.
+void ProcessThreads(SuspendedThreadsList const &suspended_threads,
+                    Frontier *frontier);
+
 // If called from the main thread, updates the main thread's TID in the thread
 // registry. We need this to handle processes that fork() without a subsequent
 // exec(), which invalidates the recorded TID. To update it, we must call

diff  --git a/compiler-rt/lib/lsan/lsan_common_linux.cpp b/compiler-rt/lib/lsan/lsan_common_linux.cpp
index ea1a4a2f569d0..a9693e02edd1c 100644
--- a/compiler-rt/lib/lsan/lsan_common_linux.cpp
+++ b/compiler-rt/lib/lsan/lsan_common_linux.cpp
@@ -15,7 +15,7 @@
 #include "sanitizer_common/sanitizer_platform.h"
 #include "lsan_common.h"
 
-#if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD)
+#if CAN_SANITIZE_LEAKS && SANITIZER_LINUX
 #include <link.h>
 
 #include "sanitizer_common/sanitizer_common.h"

diff  --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp
index f642bb807bc88..b27f324bc558f 100644
--- a/compiler-rt/lib/lsan/lsan_interceptors.cpp
+++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp
@@ -384,6 +384,16 @@ INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
 #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK
 #endif
 
+#if SANITIZER_EMSCRIPTEN
+extern "C" {
+  int emscripten_builtin_pthread_create(void *thread, void *attr,
+                                        void *(*callback)(void *), void *arg);
+  int emscripten_builtin_pthread_join(void *th, void **ret);
+  void *emscripten_builtin_malloc(size_t size);
+  void emscripten_builtin_free(void *);
+}
+#endif
+
 #if SANITIZER_INTERCEPT_STRERROR
 INTERCEPTOR(char *, strerror, int errnum) {
   __lsan::ScopedInterceptorDisabler disabler;
@@ -418,7 +428,11 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
     internal_sched_yield();
   SetCurrentThread(tid);
   ThreadStart(tid, GetTid());
+#if SANITIZER_EMSCRIPTEN
+  emscripten_builtin_free(p);
+#else
   atomic_store(&p->tid, 0, memory_order_release);
+#endif
   return callback(param);
 }
 
@@ -434,10 +448,17 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
   AdjustStackSize(attr);
   int detached = 0;
   pthread_attr_getdetachstate(attr, &detached);
+#if SANITIZER_EMSCRIPTEN
+  ThreadParam *p = (ThreadParam *) emscripten_builtin_malloc(sizeof(ThreadParam));
+  p->callback = callback;
+  p->param = param;
+  atomic_store(&p->tid, 0, memory_order_relaxed);
+#else
   ThreadParam p;
   p.callback = callback;
   p.param = param;
   atomic_store(&p.tid, 0, memory_order_relaxed);
+#endif
   int res;
   {
     // Ignore all allocations made by pthread_create: thread stack/TLS may be
@@ -445,15 +466,23 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
     // the linked list it's stored in doesn't even hold valid pointers to the
     // objects, the latter are calculated by obscure pointer arithmetic.
     ScopedInterceptorDisabler disabler;
+#if SANITIZER_EMSCRIPTEN
+    res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, p);
+#else
     res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
+#endif
   }
   if (res == 0) {
     int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
                            IsStateDetached(detached));
     CHECK_NE(tid, 0);
+#if SANITIZER_EMSCRIPTEN
+    atomic_store(&p->tid, tid, memory_order_release);
+#else
     atomic_store(&p.tid, tid, memory_order_release);
     while (atomic_load(&p.tid, memory_order_acquire) != 0)
       internal_sched_yield();
+#endif
   }
   if (attr == &myattr)
     pthread_attr_destroy(&myattr);
@@ -469,11 +498,21 @@ INTERCEPTOR(int, pthread_join, void *th, void **ret) {
   return res;
 }
 
+#if !SANITIZER_EMSCRIPTEN
 INTERCEPTOR(void, _exit, int status) {
   if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
   REAL(_exit)(status);
 }
+#endif
+
+#if SANITIZER_EMSCRIPTEN
+namespace __lsan {
 
+void InitializeInterceptors() {}
+
+} // namespace __lsan
+
+#else
 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
 
@@ -518,3 +557,4 @@ void InitializeInterceptors() {
 }
 
 } // namespace __lsan
+#endif // SANITIZER_EMSCRIPTEN

diff  --git a/compiler-rt/lib/lsan/lsan_linux.cpp b/compiler-rt/lib/lsan/lsan_linux.cpp
index 14a42b75d2af3..691ce42313687 100644
--- a/compiler-rt/lib/lsan/lsan_linux.cpp
+++ b/compiler-rt/lib/lsan/lsan_linux.cpp
@@ -12,7 +12,7 @@
 
 #include "sanitizer_common/sanitizer_platform.h"
 
-#if SANITIZER_LINUX || SANITIZER_NETBSD
+#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN
 
 #include "lsan_allocator.h"
 
@@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {}
 
 } // namespace __lsan
 
-#endif  // SANITIZER_LINUX || SANITIZER_NETBSD
+#endif // SANITIZER_LINUX

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
index f388d0d364633..7f797c2c4c15c 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
@@ -19,11 +19,14 @@
 #ifndef SANITIZER_ERRNO_CODES_H
 #define SANITIZER_ERRNO_CODES_H
 
+// XXX EMSCRIPTEN: use wasi errno codes, which is what our musl port now uses
+#include <wasi/api.h>
+
 namespace __sanitizer {
 
-#define errno_ENOMEM 12
-#define errno_EBUSY 16
-#define errno_EINVAL 22
+#define errno_ENOMEM __WASI_ERRNO_NOMEM
+#define errno_EBUSY  __WASI_ERRNO_BUSY
+#define errno_EINVAL __WASI_ERRNO_INVAL
 
 // Those might not present or their value 
diff er on 
diff erent platforms.
 extern const int errno_EOWNERDEAD;

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
index d0ffc79b06107..4e4609c27cb66 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -182,7 +182,8 @@ typedef u64  OFF64_T;
 #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
 typedef uptr operator_new_size_type;
 #else
-# if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__)
+# if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__) || \
+     SANITIZER_EMSCRIPTEN
 // Special case: 31-bit s390 has unsigned long as size_t.
 typedef unsigned long operator_new_size_type;
 # else

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 84453f1bd3008..dc5bbb6bc6cc6 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -14,7 +14,7 @@
 #include "sanitizer_platform.h"
 
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS
+    SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
@@ -101,9 +101,17 @@ extern struct ps_strings *__ps_strings;
 #define environ _environ
 #endif
 
+#if SANITIZER_EMSCRIPTEN
+#include <syscall.h>
+#include <emscripten/threading.h>
+#include <math.h>
+#include <wasi/api.h>
+#include <wasi/wasi-helpers.h>
+#endif
+
 extern char **environ;
 
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN
 // <linux/time.h>
 struct kernel_timeval {
   long tv_sec;
@@ -164,7 +172,7 @@ namespace __sanitizer {
 
 // --------------- sanitizer_libc.h
 #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
-#if !SANITIZER_S390 && !SANITIZER_OPENBSD
+#if !SANITIZER_S390 && !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN
 uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
                    u64 offset) {
 #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
@@ -177,20 +185,26 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
                           offset / 4096);
 #endif
 }
-#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD
+#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD && !SANITIZER_NETBSD
 
-#if !SANITIZER_OPENBSD
+#if !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN
 uptr internal_munmap(void *addr, uptr length) {
   return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
 }
+#endif
 
+#if !SANITIZER_OPENBSD
 int internal_mprotect(void *addr, uptr length, int prot) {
   return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
 }
 #endif
 
 uptr internal_close(fd_t fd) {
+#if SANITIZER_EMSCRIPTEN
+  return __wasi_fd_close(fd);
+#else
   return internal_syscall(SYSCALL(close), fd);
+#endif
 }
 
 uptr internal_open(const char *filename, int flags) {
@@ -211,27 +225,50 @@ uptr internal_open(const char *filename, int flags, u32 mode) {
 }
 
 uptr internal_read(fd_t fd, void *buf, uptr count) {
+#ifdef __EMSCRIPTEN__
+  __wasi_iovec_t iov = { (uint8_t *)buf, count };
+  size_t num;
+  if (__wasi_syscall_ret(__wasi_fd_read(fd, &iov, 1, &num))) {
+    return -1;
+  }
+  return num;
+#else
   sptr res;
   HANDLE_EINTR(res,
                (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count));
   return res;
+#endif
 }
 
 uptr internal_write(fd_t fd, const void *buf, uptr count) {
+#ifdef __EMSCRIPTEN__
+  __wasi_ciovec_t iov = { (const uint8_t *)buf, count };
+  size_t num;
+  if (__wasi_syscall_ret(__wasi_fd_write(fd, &iov, 1, &num))) {
+    return -1;
+  }
+  return num;
+#else
   sptr res;
   HANDLE_EINTR(res,
                (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count));
   return res;
+#endif
 }
 
 uptr internal_ftruncate(fd_t fd, uptr size) {
   sptr res;
+#if SANITIZER_EMSCRIPTEN
+  HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd,
+               0, size, 0));
+#else
   HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd,
                (OFF_T)size));
+#endif
   return res;
 }
 
-#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
+#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX || SANITIZER_EMSCRIPTEN
 static void stat64_to_stat(struct stat64 *in, struct stat *out) {
   internal_memset(out, 0, sizeof(*out));
   out->st_dev = in->st_dev;
@@ -419,7 +456,11 @@ uptr internal_rename(const char *oldpath, const char *newpath) {
 }
 
 uptr internal_sched_yield() {
+#if SANITIZER_EMSCRIPTEN
+  return 0;
+#else
   return internal_syscall(SYSCALL(sched_yield));
+#endif
 }
 
 void internal__exit(int exitcode) {
@@ -431,6 +472,8 @@ void internal__exit(int exitcode) {
   Die();  // Unreachable.
 }
 
+
+#if !SANITIZER_EMSCRIPTEN
 unsigned int internal_sleep(unsigned int seconds) {
   struct timespec ts;
   ts.tv_sec = seconds;
@@ -445,6 +488,7 @@ uptr internal_execve(const char *filename, char *const argv[],
   return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
                           (uptr)envp);
 }
+#endif  // !SANITIZER_EMSCRIPTEN
 #endif  // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
 
 // ----------------- sanitizer_common.h
@@ -472,11 +516,14 @@ tid_t GetTid() {
   return internal_syscall(SYSCALL(getthrid));
 #elif SANITIZER_SOLARIS
   return thr_self();
+#elif SANITIZER_EMSCRIPTEN
+  return (tid_t) pthread_self();
 #else
   return internal_syscall(SYSCALL(gettid));
 #endif
 }
 
+#if !SANITIZER_EMSCRIPTEN
 int TgKill(pid_t pid, tid_t tid, int sig) {
 #if SANITIZER_LINUX
   return internal_syscall(SYSCALL(tgkill), pid, tid, sig);
@@ -491,8 +538,9 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
 #endif
 }
 #endif
+#endif
 
-#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN
 u64 NanoTime() {
 #if SANITIZER_FREEBSD || SANITIZER_OPENBSD
   timeval tv;
@@ -509,12 +557,20 @@ uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
 }
 #endif  // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
 
+#if SANITIZER_EMSCRIPTEN
+int __clock_gettime(__sanitizer_clockid_t clk_id, void *tp);
+
+uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
+  return __clock_gettime(clk_id, tp);
+}
+#endif
+
 // Like getenv, but reads env directly from /proc (on Linux) or parses the
 // 'environ' array (on some others) and does not use libc. This function
 // should be called first inside __asan_init.
 const char *GetEnv(const char *name) {
 #if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \
-    SANITIZER_SOLARIS
+    SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
   if (::environ != 0) {
     uptr NameLen = internal_strlen(name);
     for (char **Env = ::environ; *Env != 0; Env++) {
@@ -584,7 +640,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
 }
 #endif
 
-#if !SANITIZER_OPENBSD
+#if !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN
 static void GetArgsAndEnv(char ***argv, char ***envp) {
 #if SANITIZER_FREEBSD
   // On FreeBSD, retrieving the argument and environment arrays is done via the
@@ -631,7 +687,7 @@ char **GetEnviron() {
   return envp;
 }
 
-#endif  // !SANITIZER_OPENBSD
+#endif  // !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN
 
 #if !SANITIZER_SOLARIS
 enum MutexState {
@@ -654,6 +710,8 @@ void BlockingMutex::Lock() {
     _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0);
 #elif SANITIZER_NETBSD
     sched_yield(); /* No userspace futex-like synchronization */
+#elif SANITIZER_EMSCRIPTEN
+    emscripten_futex_wait(m, MtxSleeping, INFINITY);
 #else
     internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT_PRIVATE, MtxSleeping,
                      0, 0, 0);
@@ -670,6 +728,8 @@ void BlockingMutex::Unlock() {
     _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0);
 #elif SANITIZER_NETBSD
                    /* No userspace futex-like synchronization */
+#elif SANITIZER_EMSCRIPTEN
+    emscripten_futex_wake(m, 1);
 #else
     internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0);
 #endif
@@ -716,11 +776,13 @@ struct linux_dirent {
 #endif
 
 #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+#if !SANITIZER_EMSCRIPTEN
 // Syscall wrappers.
 uptr internal_ptrace(int request, int pid, void *addr, void *data) {
   return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
                           (uptr)data);
 }
+#endif
 
 uptr internal_waitpid(int pid, int *status, int options) {
   return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
@@ -746,7 +808,12 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
 }
 
 uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
+#if SANITIZER_EMSCRIPTEN
+  __wasi_filesize_t result;
+  return __wasi_syscall_ret(__wasi_fd_seek(fd, offset, whence, &result)) ? -1 : result;
+#else
   return internal_syscall(SYSCALL(lseek), fd, offset, whence);
+#endif
 }
 
 #if SANITIZER_LINUX
@@ -755,12 +822,17 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
 }
 #endif
 
+#if !SANITIZER_EMSCRIPTEN
 uptr internal_sigaltstack(const void *ss, void *oss) {
   return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
 }
+#endif
 
 int internal_fork() {
-#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+#if SANITIZER_EMSCRIPTEN
+  Report("fork not supported on emscripten\n");
+  return -1;
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
   return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
 #else
   return internal_syscall(SYSCALL(fork));
@@ -844,6 +916,8 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
                           __sanitizer_sigset_t *oldset) {
 #if SANITIZER_FREEBSD || SANITIZER_OPENBSD
   return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
+#elif SANITIZER_EMSCRIPTEN
+  return NULL;
 #else
   __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
   __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
@@ -894,7 +968,7 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
 #endif
 #endif // !SANITIZER_SOLARIS
 
-#if !SANITIZER_NETBSD
+#if !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN
 // ThreadLister implementation.
 ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) {
   char task_directory_path[80];
@@ -1073,20 +1147,24 @@ uptr GetPageSize() {
   int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0);
   CHECK_EQ(rv, 0);
   return (uptr)pz;
-#elif SANITIZER_USE_GETAUXVAL
-  return getauxval(AT_PAGESZ);
 #else
   return sysconf(_SC_PAGESIZE);  // EXEC_PAGESIZE may not be trustworthy.
 #endif
 }
 #endif // !SANITIZER_ANDROID
 
+#if SANITIZER_EMSCRIPTEN
+extern "C" uptr emscripten_get_module_name(char *buf, uptr buf_len);
+#endif
+
 #if !SANITIZER_OPENBSD
 uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
 #if SANITIZER_SOLARIS
   const char *default_module_name = getexecname();
   CHECK_NE(default_module_name, NULL);
   return internal_snprintf(buf, buf_len, "%s", default_module_name);
+#elif SANITIZER_EMSCRIPTEN
+  return emscripten_get_module_name(buf, buf_len);
 #else
 #if SANITIZER_FREEBSD || SANITIZER_NETBSD
 #if SANITIZER_FREEBSD
@@ -1975,11 +2053,9 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
 # endif
   *bp = ucontext->uc_mcontext.gregs[11];
   *sp = ucontext->uc_mcontext.gregs[15];
-#elif defined(__riscv)
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.__gregs[REG_PC];
-  *bp = ucontext->uc_mcontext.__gregs[REG_S0];
-  *sp = ucontext->uc_mcontext.__gregs[REG_SP];
+#elif SANITIZER_EMSCRIPTEN
+  Report("GetPcSpBp not implemented on emscripten");
+  Abort();
 #else
 # error "Unsupported arch"
 #endif

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
index c28347ad963a7..d73b539c3cdb8 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
@@ -14,7 +14,7 @@
 
 #include "sanitizer_platform.h"
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||                \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS
+    SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform_limits_freebsd.h"

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
index c68bfa2587558..6d098e3a78269 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
@@ -15,7 +15,7 @@
 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
   !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(_WIN32) && \
   !defined(__Fuchsia__) && !defined(__rtems__) && \
-  !(defined(__sun__) && defined(__svr4__))
+  !(defined(__sun__) && defined(__svr4__)) && !defined(__EMSCRIPTEN__)
 # error "This operating system is not supported"
 #endif
 
@@ -110,9 +110,16 @@
 # define SANITIZER_RTEMS 0
 #endif
 
+#if defined(__EMSCRIPTEN__)
+# define SANITIZER_EMSCRIPTEN 1
+#else
+# define SANITIZER_EMSCRIPTEN 0
+#endif
+
 #define SANITIZER_POSIX \
   (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \
-    SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS)
+    SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS || \
+    SANITIZER_EMSCRIPTEN)
 
 #if __LP64__ || defined(_WIN64)
 #  define SANITIZER_WORDSIZE 64

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 4cc69af1241da..658259830f3d1 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -138,12 +138,24 @@
 # define SI_POSIX_NOT_MAC 0
 #endif
 
+#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN
+# define SI_POSIX_NOT_EMSCRIPTEN 1
+#else
+# define SI_POSIX_NOT_EMSCRIPTEN 0
+#endif
+
 #if SANITIZER_LINUX && !SANITIZER_FREEBSD
 # define SI_LINUX_NOT_FREEBSD 1
 # else
 # define SI_LINUX_NOT_FREEBSD 0
 #endif
 
+#if SANITIZER_EMSCRIPTEN
+# define SI_EMSCRIPTEN 1
+#else
+# define SI_EMSCRIPTEN 0
+#endif
+
 #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA)
 #define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA
@@ -271,7 +283,7 @@
 #define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX
 #define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX
 #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX
-#define SANITIZER_INTERCEPT_IOCTL SI_POSIX
+#define SANITIZER_INTERCEPT_IOCTL SI_POSIX && !SI_EMSCRIPTEN
 #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX
 #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
 #define SANITIZER_INTERCEPT_READDIR SI_POSIX
@@ -314,7 +326,7 @@
   SI_SOLARIS)
 #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS
-#define SANITIZER_INTERCEPT_STRERROR SI_POSIX
+#define SANITIZER_INTERCEPT_STRERROR SI_POSIX_NOT_EMSCRIPTEN
 #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX
 #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_SCANDIR \

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
index aa845df4dde48..c44449aee09a6 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
@@ -13,7 +13,7 @@
 
 #include "sanitizer_platform.h"
 
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN
 // Tests in this file assume that off_t-dependent data structures match the
 // libc ABI. For example, struct dirent here is what readdir() function (as
 // exported from libc) returns, and not the user-facing "dirent", which
@@ -57,7 +57,7 @@
 #include <net/route.h>
 #endif
 
-#if !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
 #include <fstab.h>
 #include <sys/mount.h>
 #include <sys/timeb.h>
@@ -200,7 +200,7 @@ namespace __sanitizer {
   unsigned struct_statfs64_sz = sizeof(struct statfs64);
 #endif // SANITIZER_MAC && !SANITIZER_IOS
 
-#if !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
   unsigned struct_fstab_sz = sizeof(struct fstab);
   unsigned struct_statfs_sz = sizeof(struct statfs);
   unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
@@ -389,7 +389,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   // ioctl arguments
   unsigned struct_ifreq_sz = sizeof(struct ifreq);
   unsigned struct_termios_sz = sizeof(struct termios);
+
+#if !SANITIZER_EMSCRIPTEN
   unsigned struct_winsize_sz = sizeof(struct winsize);
+#endif
 
 #if SANITIZER_LINUX
   unsigned struct_arpreq_sz = sizeof(struct arpreq);
@@ -471,15 +474,18 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
 #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
 
-#if !SANITIZER_ANDROID && !SANITIZER_MAC
+#if !SANITIZER_ANDROID && !SANITIZER_MAC && !SANITIZER_EMSCRIPTEN
   unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
   unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
 #endif
 
+#if !SANITIZER_EMSCRIPTEN
   const unsigned long __sanitizer_bufsiz = BUFSIZ;
+#endif
 
   const unsigned IOCTL_NOT_PRESENT = 0;
 
+#if !SANITIZER_EMSCRIPTEN
   unsigned IOCTL_FIOASYNC = FIOASYNC;
   unsigned IOCTL_FIOCLEX = FIOCLEX;
   unsigned IOCTL_FIOGETOWN = FIOGETOWN;
@@ -528,6 +534,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
   unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
 #endif
+#endif
 
 #if SANITIZER_LINUX
   unsigned IOCTL_EVIOCGABS = EVIOCGABS(0);
@@ -1018,6 +1025,7 @@ CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len);
 #endif
 
 COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
+#if !SANITIZER_EMSCRIPTEN
 CHECK_SIZE_AND_OFFSET(dirent, d_ino);
 #if SANITIZER_MAC
 CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
@@ -1027,6 +1035,7 @@ CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
 CHECK_SIZE_AND_OFFSET(dirent, d_off);
 #endif
 CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
+#endif // !SANITIZER_EMSCRIPTEN
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
 COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64));
@@ -1046,6 +1055,7 @@ CHECK_SIZE_AND_OFFSET(pollfd, revents);
 
 CHECK_TYPE_SIZE(nfds_t);
 
+#if !SANITIZER_EMSCRIPTEN
 CHECK_TYPE_SIZE(sigset_t);
 
 COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
@@ -1060,6 +1070,7 @@ CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags);
 #if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32)
 CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer);
 #endif
+#endif // !SANITIZER_EMSCRIPTEN
 
 #if SANITIZER_LINUX
 CHECK_TYPE_SIZE(__sysctl_args);
@@ -1113,7 +1124,9 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_freq);
 CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
 #endif
 
+#if !SANITIZER_EMSCRIPTEN
 CHECK_TYPE_SIZE(ether_addr);
+#endif
 
 #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
 CHECK_TYPE_SIZE(ipc_perm);
@@ -1151,7 +1164,7 @@ CHECK_TYPE_SIZE(clock_t);
 CHECK_TYPE_SIZE(clockid_t);
 #endif
 
-#if !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
 CHECK_TYPE_SIZE(ifaddrs);
 CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
 CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
@@ -1181,7 +1194,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
 COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo));
 #endif
 
-#if !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
 CHECK_TYPE_SIZE(timeb);
 CHECK_SIZE_AND_OFFSET(timeb, time);
 CHECK_SIZE_AND_OFFSET(timeb, millitm);

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 5337b26b29b8b..b0896f86720b3 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -14,7 +14,7 @@
 #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
 #define SANITIZER_PLATFORM_LIMITS_POSIX_H
 
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN
 
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform.h"
@@ -503,7 +503,7 @@ typedef long long __sanitizer_clock_t;
 typedef long __sanitizer_clock_t;
 #endif
 
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN
 typedef int __sanitizer_clockid_t;
 #endif
 
@@ -556,6 +556,8 @@ struct __sanitizer_sigset_t {
   // The size is determined by looking at sizeof of real sigset_t on linux.
   uptr val[128 / sizeof(uptr)];
 };
+#elif SANITIZER_EMSCRIPTEN
+typedef unsigned long __sanitizer_sigset_t;
 #endif
 
 struct __sanitizer_siginfo {

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp
index d890a3a317737..fea3483506f26 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp
@@ -220,6 +220,16 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
   return (end1 < start2) || (end2 < start1);
 }
 
+#if SANITIZER_EMSCRIPTEN
+bool MemoryRangeIsAvailable(uptr /*range_start*/, uptr /*range_end*/) {
+  // TODO: actually implement this.
+  return true;
+}
+
+void DumpProcessMap() {
+  Report("Cannot dump memory map on emscripten");
+}
+#else
 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
 // When the shadow is mapped only a single thread usually exists (plus maybe
 // several worker threads on Mac, which aren't expected to map big chunks of
@@ -252,6 +262,7 @@ void DumpProcessMap() {
   Report("End of process memory map.\n");
   UnmapOrDie(filename, kBufSize);
 }
+#endif
 
 const char *GetPwd() {
   return GetEnv("PWD");
@@ -272,6 +283,10 @@ void ReportFile::Write(const char *buffer, uptr length) {
 }
 
 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
+#if SANITIZER_EMSCRIPTEN
+  // Code is not mapped in memory in Emscripten, so this operation is meaningless
+  // and thus always fails.
+#else
   MemoryMappingLayout proc_maps(/*cache_enabled*/false);
   InternalScopedString buff(kMaxPathLength);
   MemoryMappedSegment segment(buff.data(), kMaxPathLength);
@@ -283,6 +298,7 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
       return true;
     }
   }
+#endif
   return false;
 }
 

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
index 304b3a01a08b6..3c0c91e7cac31 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -215,7 +215,9 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
   // Set the alternate signal stack for the main thread.
   // This will cause SetAlternateSignalStack to be called twice, but the stack
   // will be actually set only once.
+#if !SANITIZER_EMSCRIPTEN
   if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
+#endif
   MaybeInstallSigaction(SIGSEGV, handler);
   MaybeInstallSigaction(SIGBUS, handler);
   MaybeInstallSigaction(SIGABRT, handler);
@@ -275,6 +277,11 @@ bool SignalContext::IsStackOverflow() const {
 #endif  // SANITIZER_GO
 
 bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+#if SANITIZER_EMSCRIPTEN
+  // Avoid pulling in __sys_pipe for the trick below, which doesn't work on
+  // WebAssembly anyways because there are no memory protections.
+  return true;
+#else
   uptr page_size = GetPageSizeCached();
   // Checking too large memory ranges is slow.
   CHECK_LT(size, page_size * 10);
@@ -294,6 +301,7 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
   internal_close(sock_pair[0]);
   internal_close(sock_pair[1]);
   return result;
+#endif // SANITIZER_EMSCRIPTEN
 }
 
 void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
@@ -301,7 +309,9 @@ void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
   // to read the file mappings from /proc/self/maps. Luckily, neither the
   // process will be able to load additional libraries, so it's fine to use the
   // cached mappings.
+#ifndef SANITIZER_EMSCRIPTEN
   MemoryMappingLayout::CacheMemoryMappings();
+#endif
 }
 
 static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags,

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
index ef14fb704eed3..7029da649eb86 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
@@ -26,9 +26,11 @@ uptr StackTrace::GetNextInstructionPc(uptr pc) {
 #endif
 }
 
+#if !defined(__EMSCRIPTEN__)
 uptr StackTrace::GetCurrentPc() {
   return GET_CALLER_PC();
 }
+#endif
 
 void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
   size = cnt + !!extra_top_pc;
@@ -39,8 +41,8 @@ void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
   top_frame_bp = 0;
 }
 
-// Sparc implemention is in its own file.
-#if !defined(__sparc__)
+// Sparc and Emscripten implementions are in their own files.
+#if !defined(__sparc__) && !defined(__EMSCRIPTEN__)
 
 // In GCC on ARM bp points to saved lr, not fp, so we should check the next
 // cell in stack to be a saved frame pointer. GetCanonicFrame returns the

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
index f1f29e9f32ee8..ab71cb6a86a0b 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -33,7 +33,7 @@ static const u32 kStackTraceMax = 256;
 // Fast unwind is the only option on Mac for now; we will need to
 // revisit this macro when slow unwind works on Mac, see
 // https://github.com/google/sanitizers/issues/137
-#if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS
+#if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN
 # define SANITIZER_CAN_SLOW_UNWIND 0
 #else
 # define SANITIZER_CAN_SLOW_UNWIND 1
@@ -65,6 +65,9 @@ struct StackTrace {
     return request_fast_unwind;
   }
 
+#if SANITIZER_EMSCRIPTEN
+  static bool snapshot_stack;
+#endif
   static uptr GetCurrentPc();
   static inline uptr GetPreviousInstructionPc(uptr pc);
   static uptr GetNextInstructionPc(uptr pc);

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
index 4ef305cf17991..2559349319b34 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
@@ -28,9 +28,15 @@ void StackTrace::Print() const {
   int dedup_frames = common_flags()->dedup_token_length;
   uptr frame_num = 0;
   for (uptr i = 0; i < size && trace[i]; i++) {
+#if !SANITIZER_EMSCRIPTEN
     // PCs in stack traces are actually the return addresses, that is,
     // addresses of the next instructions after the call.
     uptr pc = GetPreviousInstructionPc(trace[i]);
+#else
+    // On Emscripten, the stack traces are obtained from JavaScript, and the
+    // addresses are not return addresses.
+    uptr pc = trace[i];
+#endif
     SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
     CHECK(frames);
     for (SymbolizedStack *cur = frames; cur; cur = cur->next) {

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
index c123ecb11206c..3918348b47bec 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
@@ -12,7 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
-#if SANITIZER_POSIX
+#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN
 #include "sanitizer_allocator_internal.h"
 #include "sanitizer_common.h"
 #include "sanitizer_file.h"

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
index c26724ceb7a7d..4783459fba52a 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -39,7 +39,21 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info,
 }
 #endif
 
-#if !SANITIZER_FUCHSIA
+#if SANITIZER_EMSCRIPTEN
+#include <emscripten/em_asm.h>
+
+static INLINE bool ReportSupportsColors() {
+  return !!EM_ASM_INT({
+    var setting = Module['printWithColors'];
+    if (setting != null) {
+      return setting;
+    } else {
+      return ENVIRONMENT_IS_NODE && process.stderr.isTTY;
+    }
+  });
+}
+
+#elif !SANITIZER_FUCHSIA
 
 bool ReportFile::SupportsColors() {
   SpinMutexLock l(mu);
@@ -56,7 +70,7 @@ static INLINE bool ReportSupportsColors() {
 // Fuchsia's logs always go through post-processing that handles colorization.
 static INLINE bool ReportSupportsColors() { return true; }
 
-#endif  // !SANITIZER_FUCHSIA
+#endif  // SANITIZER_EMSCRIPTEN, !SANITIZER_FUCHSIA
 
 bool ColorizeReports() {
   // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
index a43ce3efab127..f64b403d62aa8 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
@@ -13,7 +13,7 @@
 // NetBSD uses libc calls directly
 #if !SANITIZER_NETBSD
 
-#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_SOLARIS
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 # define SYSCALL(name) SYS_ ## name
 #else
 # define SYSCALL(name) __NR_ ## name

diff  --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc
index 33a8dfcde0269..7e7216c5b4ab7 100644
--- a/compiler-rt/lib/ubsan/ubsan_checks.inc
+++ b/compiler-rt/lib/ubsan/ubsan_checks.inc
@@ -18,11 +18,6 @@
 
 UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
 UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
-UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow")
-UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset",
-            "pointer-overflow")
-UBSAN_CHECK(NullptrAfterNonZeroOffset, "nullptr-after-nonzero-offset",
-            "pointer-overflow")
 UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow")
 UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment")
 UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment")

diff  --git a/compiler-rt/lib/ubsan/ubsan_diag.cpp b/compiler-rt/lib/ubsan/ubsan_diag.cpp
index 1b2828d236d6e..529cc6985763b 100644
--- a/compiler-rt/lib/ubsan/ubsan_diag.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_diag.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_diag.cpp ----------------------------------------------------===//
+//===-- ubsan_diag.cc -----------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -404,7 +404,7 @@ static const char *kSuppressionTypes[] = {
 
 void __ubsan::InitializeSuppressions() {
   CHECK_EQ(nullptr, suppression_ctx);
-  suppression_ctx = new (suppression_placeholder)
+  suppression_ctx = new (suppression_placeholder) // NOLINT
       SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
   suppression_ctx->ParseFromFile(flags()->suppressions);
 }

diff  --git a/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp
index 300179adae28c..c22fd17499725 100644
--- a/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_diag_standalone.cpp -----------------------------------------===//
+//===-- ubsan_diag_standalone.cc ------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_flags.cpp b/compiler-rt/lib/ubsan/ubsan_flags.cpp
index 721c2273f133a..210b831507d2e 100644
--- a/compiler-rt/lib/ubsan/ubsan_flags.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_flags.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_flags.cpp ---------------------------------------------------===//
+//===-- ubsan_flags.cc ----------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -19,6 +19,11 @@
 
 #include <stdlib.h>
 
+#if SANITIZER_EMSCRIPTEN
+extern "C" void emscripten_builtin_free(void *);
+#include <emscripten/em_asm.h>
+#endif
+
 namespace __ubsan {
 
 const char *MaybeCallUbsanDefaultOptions() {
@@ -54,7 +59,12 @@ void InitializeFlags() {
   {
     CommonFlags cf;
     cf.CopyFrom(*common_flags());
+    cf.print_summary = false;
+#if !SANITIZER_EMSCRIPTEN
+    // getenv on emscripten uses malloc, which we can't when using some sanitizers.
+    // You can't run external symbolizers anyway.
     cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
+#endif
     OverrideCommonFlags(cf);
   }
 
@@ -67,8 +77,20 @@ void InitializeFlags() {
 
   // Override from user-specified string.
   parser.ParseString(MaybeCallUbsanDefaultOptions());
+
   // Override from environment variable.
-  parser.ParseStringFromEnv("UBSAN_OPTIONS");
+#if SANITIZER_EMSCRIPTEN
+  char *options = (char*) EM_ASM_INT({
+    return withBuiltinMalloc(function () {
+      return allocateUTF8(Module['UBSAN_OPTIONS'] || 0);
+    });
+  });
+  parser.ParseString(options);
+  emscripten_builtin_free(options);
+#else
+  parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+#endif // SANITIZER_EMSCRIPTEN
+
   InitializeCommonFlags();
   if (Verbosity()) ReportUnrecognizedFlags();
 

diff  --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp
index 3f9da75a12a8d..938ac89750f36 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_handlers.cpp ------------------------------------------------===//
+//===-- ubsan_handlers.cc -------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -691,33 +691,14 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data,
                                       ValueHandle Result,
                                       ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
-  ErrorType ET;
-
-  if (Base == 0 && Result == 0)
-    ET = ErrorType::NullptrWithOffset;
-  else if (Base == 0 && Result != 0)
-    ET = ErrorType::NullptrWithNonZeroOffset;
-  else if (Base != 0 && Result == 0)
-    ET = ErrorType::NullptrAfterNonZeroOffset;
-  else
-    ET = ErrorType::PointerOverflow;
+  ErrorType ET = ErrorType::PointerOverflow;
 
   if (ignoreReport(Loc, Opts, ET))
     return;
 
   ScopedReport R(Opts, Loc, ET);
 
-  if (ET == ErrorType::NullptrWithOffset) {
-    Diag(Loc, DL_Error, ET, "applying zero offset to null pointer");
-  } else if (ET == ErrorType::NullptrWithNonZeroOffset) {
-    Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer")
-        << Result;
-  } else if (ET == ErrorType::NullptrAfterNonZeroOffset) {
-    Diag(
-        Loc, DL_Error, ET,
-        "applying non-zero offset to non-null pointer %0 produced null pointer")
-        << (void *)Base;
-  } else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {
+  if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {
     if (Base > Result)
       Diag(Loc, DL_Error, ET,
            "addition of unsigned offset to %0 overflowed to %1")

diff  --git a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp
index 2a6d558de0342..9c324cc19a11f 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_handlers_cxx.cpp --------------------------------------------===//
+//===-- ubsan_handlers_cxx.cc ---------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_init.cpp b/compiler-rt/lib/ubsan/ubsan_init.cpp
index 1a3b7d3726743..f0bbe1ef10768 100644
--- a/compiler-rt/lib/ubsan/ubsan_init.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_init.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_init.cpp ----------------------------------------------------===//
+//===-- ubsan_init.cc -----------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp
index 91c3f57b424b9..323c2c1f9a474 100644
--- a/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_init_standalone.cpp -----------------------------------------===//
+//===-- ubsan_init_standalone.cc ------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp b/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp
index fabbf919a4022..bf344a2a9fcdb 100644
--- a/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_init_standalone_preinit.cpp --------------------------------===//
+//===-- ubsan_init_standalone_preinit.cc ---------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_monitor.cpp b/compiler-rt/lib/ubsan/ubsan_monitor.cpp
index d064e95f76f72..cb97a8ff1b887 100644
--- a/compiler-rt/lib/ubsan/ubsan_monitor.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_monitor.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_monitor.cpp ---------------------------------------*- C++ -*-===//
+//===-- ubsan_monitor.cc ----------------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_platform.h b/compiler-rt/lib/ubsan/ubsan_platform.h
index 71d7fb18c9b3a..684af5a5c179b 100644
--- a/compiler-rt/lib/ubsan/ubsan_platform.h
+++ b/compiler-rt/lib/ubsan/ubsan_platform.h
@@ -16,7 +16,8 @@
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) ||        \
     defined(__NetBSD__) || defined(__OpenBSD__) || \
     (defined(__sun__) && defined(__svr4__)) || \
-    defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__)
+    defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__) || \
+    defined(__EMSCRIPTEN__)
 # define CAN_SANITIZE_UB 1
 #else
 # define CAN_SANITIZE_UB 0

diff  --git a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
index 2c91db8ca3974..5f8a8c0662d4f 100644
--- a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
@@ -1,4 +1,5 @@
-//=-- ubsan_signals_standalone.cpp ----------------------------------------===//
+//=-- ubsan_signals_standalone.cc
+//------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -26,7 +27,7 @@
 // debuggerd handler, but before the ART handler.
 // * Interceptors don't work at all when ubsan runtime is loaded late, ex. when
 // it is part of an APK that does not use wrap.sh method.
-#if SANITIZER_FUCHSIA || SANITIZER_ANDROID
+#if SANITIZER_FUCHSIA || SANITIZER_ANDROID || SANITIZER_EMSCRIPTEN
 
 namespace __ubsan {
 void InitializeDeadlySignals() {}
@@ -45,9 +46,8 @@ namespace __ubsan {
 
 static void OnStackUnwind(const SignalContext &sig, const void *,
                           BufferedStackTrace *stack) {
-  ubsan_GetStackTrace(stack, kStackTraceMax,
-                      StackTrace::GetNextInstructionPc(sig.pc), sig.bp,
-                      sig.context, common_flags()->fast_unwind_on_fatal);
+  ubsan_GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context,
+                common_flags()->fast_unwind_on_fatal);
 }
 
 static void UBsanOnDeadlySignal(int signo, void *siginfo, void *context) {

diff  --git a/compiler-rt/lib/ubsan/ubsan_type_hash.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash.cpp
index 8f4b9aee50bbd..431495672b55a 100644
--- a/compiler-rt/lib/ubsan/ubsan_type_hash.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_type_hash.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_type_hash.cpp -----------------------------------------------===//
+//===-- ubsan_type_hash.cc ------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -11,7 +11,7 @@
 // permitted to use language features which require a C++ ABI library.
 //
 // Most of the implementation lives in an ABI-specific source file
-// (ubsan_type_hash_{itanium,win}.cpp).
+// (ubsan_type_hash_{itanium,win}.cc).
 //
 //===----------------------------------------------------------------------===//
 

diff  --git a/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp
index 97846d4dd434b..c4b048f20a8c9 100644
--- a/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_type_hash_itanium.cpp ---------------------------------------===//
+//===-- ubsan_type_hash_itanium.cc ----------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp
index 45dcb758ec445..c7b2e45af4e66 100644
--- a/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_type_hash_win.cpp -------------------------------------------===//
+//===-- ubsan_type_hash_win.cc --------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_value.cpp b/compiler-rt/lib/ubsan/ubsan_value.cpp
index 60f0b5c993482..ba336a6673ca7 100644
--- a/compiler-rt/lib/ubsan/ubsan_value.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_value.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_value.cpp ---------------------------------------------------===//
+//===-- ubsan_value.cc ----------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp b/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp
index 5ac7fc3e08e4c..fd39e210af0a8 100644
--- a/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_win_dll_thunk.cpp -------------------------------------------===//
+//===-- ubsan_win_dll_thunk.cc --------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp b/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
index 00722b4033a53..87ada6131cde0 100644
--- a/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_win_dynamic_runtime_thunk.cpp -------------------------------===//
+//===-- ubsan_win_dynamic_runtime_thunk.cc --------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp b/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp
index 01db0c0ce78ab..8cf6344ce1d80 100644
--- a/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_win_weak_interception.cpp -----------------------------------===//
+//===-- ubsan_win_weak_interception.cc ------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

diff  --git a/libcxx/include/__config b/libcxx/include/__config
index ccce227f4d6bd..5cedbe4a44fb2 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -99,7 +99,8 @@
 // Previously libc++ used "unsigned int" exclusively.
 #  define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION
 // Unstable attempt to provide a more optimized std::function
-#  define _LIBCPP_ABI_OPTIMIZED_FUNCTION
+// XXX EMSCRIPTEN https://github.com/emscripten-core/emscripten/issues/11022
+//#  define _LIBCPP_ABI_OPTIMIZED_FUNCTION
 // All the regex constants must be distinct and nonzero.
 #  define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO
 #elif _LIBCPP_ABI_VERSION == 1
@@ -307,7 +308,7 @@
    // random data even when using sandboxing mechanisms such as chroots,
    // Capsicum, etc.
 #  define _LIBCPP_USING_ARC4_RANDOM
-#elif defined(__Fuchsia__) || defined(__wasi__)
+#elif defined(__Fuchsia__) || defined(__wasi__) || defined(__EMSCRIPTEN__)
 #  define _LIBCPP_USING_GETENTROPY
 #elif defined(__native_client__)
    // NaCl's sandbox (which PNaCl also runs in) doesn't allow filesystem access,
@@ -908,7 +909,7 @@ typedef unsigned int   char32_t;
 
 #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
 // Most unix variants have catopen.  These are the specific ones that don't.
-#  if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION)
+#  if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__) // XXX Emscripten catopen always returns -1
 #    define _LIBCPP_HAS_CATOPEN 1
 #  endif
 #endif
@@ -1122,6 +1123,7 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
       defined(__APPLE__) || \
       defined(__CloudABI__) || \
       defined(__sun__) || \
+      defined(__EMSCRIPTEN__) || \
       (defined(__MINGW32__) && __has_include(<pthread.h>))
 #    define _LIBCPP_HAS_THREAD_API_PTHREAD
 #  elif defined(__Fuchsia__)

diff  --git a/libcxx/include/__sso_allocator b/libcxx/include/__sso_allocator
index 393012873848c..c381068a3614b 100644
--- a/libcxx/include/__sso_allocator
+++ b/libcxx/include/__sso_allocator
@@ -40,9 +40,9 @@ public:
     typedef _Tp*              pointer;
     typedef _Tp               value_type;
 
-    _LIBCPP_INLINE_VISIBILITY __sso_allocator() throw() : __allocated_(false) {}
-    _LIBCPP_INLINE_VISIBILITY __sso_allocator(const __sso_allocator&) throw() : __allocated_(false) {}
-    template <class _Up> _LIBCPP_INLINE_VISIBILITY __sso_allocator(const __sso_allocator<_Up, _Np>&) throw()
+    _LIBCPP_INLINE_VISIBILITY __sso_allocator() _NOEXCEPT : __allocated_(false) {}
+    _LIBCPP_INLINE_VISIBILITY __sso_allocator(const __sso_allocator&) _NOEXCEPT : __allocated_(false) {}
+    template <class _Up> _LIBCPP_INLINE_VISIBILITY __sso_allocator(const __sso_allocator<_Up, _Np>&) _NOEXCEPT
          : __allocated_(false) {}
 private:
     __sso_allocator& operator=(const __sso_allocator&);
@@ -63,7 +63,7 @@ public:
         else
             _VSTD::__libcpp_deallocate(__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
     }
-    _LIBCPP_INLINE_VISIBILITY size_type max_size() const throw() {return size_type(~0) / sizeof(_Tp);}
+    _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return size_type(~0) / sizeof(_Tp);}
 
     _LIBCPP_INLINE_VISIBILITY
     bool operator==(__sso_allocator& __a) const {return &buf_ == &__a.buf_;}

diff  --git a/libcxx/include/codecvt b/libcxx/include/codecvt
index 5ea411ea781b7..05fa765c31804 100644
--- a/libcxx/include/codecvt
+++ b/libcxx/include/codecvt
@@ -102,11 +102,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -137,11 +137,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -172,11 +172,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <class _Elem, unsigned long _Maxcode = 0x10ffff,
@@ -225,11 +225,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -260,11 +260,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -295,11 +295,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -330,11 +330,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -365,11 +365,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -400,11 +400,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <class _Elem, unsigned long _Maxcode = 0x10ffff,
@@ -453,11 +453,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -488,11 +488,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <>
@@ -523,11 +523,11 @@ protected:
     virtual result
         do_unshift(state_type& __st,
                    extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const;
-    virtual int do_encoding() const throw();
-    virtual bool do_always_noconv() const throw();
+    virtual int do_encoding() const _NOEXCEPT;
+    virtual bool do_always_noconv() const _NOEXCEPT;
     virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end,
                           size_t __mx) const;
-    virtual int do_max_length() const throw();
+    virtual int do_max_length() const _NOEXCEPT;
 };
 
 template <class _Elem, unsigned long _Maxcode = 0x10ffff,

diff  --git a/libcxx/include/ios b/libcxx/include/ios
index 88efefb46ff2b..f26b928906d77 100644
--- a/libcxx/include/ios
+++ b/libcxx/include/ios
@@ -431,7 +431,7 @@ class _LIBCPP_EXCEPTION_ABI ios_base::failure
 public:
     explicit failure(const string& __msg, const error_code& __ec = io_errc::stream);
     explicit failure(const char* __msg, const error_code& __ec = io_errc::stream);
-    virtual ~failure() throw();
+    virtual ~failure() _NOEXCEPT;
 };
 
 _LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY

diff  --git a/libcxx/include/memory b/libcxx/include/memory
index 34c3e0c0d8d1e..250721d2ebdc7 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -2134,39 +2134,39 @@ private:
 public:
     typedef _Tp element_type;
 
-    _LIBCPP_INLINE_VISIBILITY explicit auto_ptr(_Tp* __p = 0) throw() : __ptr_(__p) {}
-    _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr& __p) throw() : __ptr_(__p.release()) {}
-    template<class _Up> _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr<_Up>& __p) throw()
+    _LIBCPP_INLINE_VISIBILITY explicit auto_ptr(_Tp* __p = 0) _NOEXCEPT : __ptr_(__p) {}
+    _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr& __p) _NOEXCEPT : __ptr_(__p.release()) {}
+    template<class _Up> _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr<_Up>& __p) _NOEXCEPT
         : __ptr_(__p.release()) {}
-    _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr& __p) throw()
+    _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr& __p) _NOEXCEPT
         {reset(__p.release()); return *this;}
-    template<class _Up> _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr<_Up>& __p) throw()
+    template<class _Up> _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr<_Up>& __p) _NOEXCEPT
         {reset(__p.release()); return *this;}
-    _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr_ref<_Tp> __p) throw()
+    _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr_ref<_Tp> __p) _NOEXCEPT
         {reset(__p.__ptr_); return *this;}
-    _LIBCPP_INLINE_VISIBILITY ~auto_ptr() throw() {delete __ptr_;}
+    _LIBCPP_INLINE_VISIBILITY ~auto_ptr() _NOEXCEPT {delete __ptr_;}
 
-    _LIBCPP_INLINE_VISIBILITY _Tp& operator*() const throw()
+    _LIBCPP_INLINE_VISIBILITY _Tp& operator*() const _NOEXCEPT
         {return *__ptr_;}
-    _LIBCPP_INLINE_VISIBILITY _Tp* operator->() const throw() {return __ptr_;}
-    _LIBCPP_INLINE_VISIBILITY _Tp* get() const throw() {return __ptr_;}
-    _LIBCPP_INLINE_VISIBILITY _Tp* release() throw()
+    _LIBCPP_INLINE_VISIBILITY _Tp* operator->() const _NOEXCEPT {return __ptr_;}
+    _LIBCPP_INLINE_VISIBILITY _Tp* get() const _NOEXCEPT {return __ptr_;}
+    _LIBCPP_INLINE_VISIBILITY _Tp* release() _NOEXCEPT
     {
         _Tp* __t = __ptr_;
         __ptr_ = 0;
         return __t;
     }
-    _LIBCPP_INLINE_VISIBILITY void reset(_Tp* __p = 0) throw()
+    _LIBCPP_INLINE_VISIBILITY void reset(_Tp* __p = 0) _NOEXCEPT
     {
         if (__ptr_ != __p)
             delete __ptr_;
         __ptr_ = __p;
     }
 
-    _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr_ref<_Tp> __p) throw() : __ptr_(__p.__ptr_) {}
-    template<class _Up> _LIBCPP_INLINE_VISIBILITY operator auto_ptr_ref<_Up>() throw()
+    _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr_ref<_Tp> __p) _NOEXCEPT : __ptr_(__p.__ptr_) {}
+    template<class _Up> _LIBCPP_INLINE_VISIBILITY operator auto_ptr_ref<_Up>() _NOEXCEPT
         {auto_ptr_ref<_Up> __t; __t.__ptr_ = release(); return __t;}
-    template<class _Up> _LIBCPP_INLINE_VISIBILITY operator auto_ptr<_Up>() throw()
+    template<class _Up> _LIBCPP_INLINE_VISIBILITY operator auto_ptr<_Up>() _NOEXCEPT
         {return auto_ptr<_Up>(release());}
 };
 

diff  --git a/libcxx/include/regex b/libcxx/include/regex
index 5ac9e325e136f..0fa1ca75c7b5b 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -977,7 +977,7 @@ class _LIBCPP_EXCEPTION_ABI regex_error
     regex_constants::error_type __code_;
 public:
     explicit regex_error(regex_constants::error_type __ecode);
-    virtual ~regex_error() throw();
+    virtual ~regex_error() _NOEXCEPT;
      _LIBCPP_INLINE_VISIBILITY
     regex_constants::error_type code() const {return __code_;}
 };

diff  --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo
index 27601769a83be..645a1c8890f1f 100644
--- a/libcxx/include/typeinfo
+++ b/libcxx/include/typeinfo
@@ -301,6 +301,9 @@ public:
       return __impl::__hash(__type_name);
     }
 
+    // XXX Emscripten: adding `always_inline` fixes
+    // https://github.com/emscripten-core/emscripten/issues/13330
+    __attribute__((always_inline))
     _LIBCPP_INLINE_VISIBILITY
     bool operator==(const type_info& __arg) const _NOEXCEPT
     {

diff  --git a/libcxx/src/include/config_elast.h b/libcxx/src/include/config_elast.h
index 501cbc4ffebaa..56e1a95b54edb 100644
--- a/libcxx/src/include/config_elast.h
+++ b/libcxx/src/include/config_elast.h
@@ -29,6 +29,8 @@
 #define _LIBCPP_ELAST 4095
 #elif defined(__APPLE__)
 // No _LIBCPP_ELAST needed on Apple
+#elif defined(__EMSCRIPTEN__) // XXX EMSCRIPTEN added ELAST value
+#define _LIBCPP_ELAST 256
 #elif defined(__sun__)
 #define _LIBCPP_ELAST ESTALE
 #elif defined(_LIBCPP_MSVCRT_LIKE)

diff  --git a/libcxx/src/ios.cpp b/libcxx/src/ios.cpp
index 2dc84be828739..92717138885a5 100644
--- a/libcxx/src/ios.cpp
+++ b/libcxx/src/ios.cpp
@@ -84,7 +84,7 @@ ios_base::failure::failure(const char* msg, const error_code& ec)
 {
 }
 
-ios_base::failure::~failure() throw()
+ios_base::failure::~failure() _NOEXCEPT
 {
 }
 

diff  --git a/libcxx/src/iostream.cpp b/libcxx/src/iostream.cpp
index ad1920abc6572..874c856030211 100644
--- a/libcxx/src/iostream.cpp
+++ b/libcxx/src/iostream.cpp
@@ -77,7 +77,7 @@ __asm__("?wclog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream at _WU?$char_t
 #endif
 ;
 
-_LIBCPP_HIDDEN ios_base::Init __start_std_streams;
+_LIBCPP_HIDDEN ios_base::Init __attribute__((init_priority(101))) __start_std_streams; // XXX EMSCRIPTEN: ensure a high priority for this constructor, see #3824
 
 // On Windows the TLS storage for locales needs to be initialized before we create
 // the standard streams, otherwise it may not be alive during program termination

diff  --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp
index 901e78565857b..bd0b42f7cb7c0 100644
--- a/libcxx/src/new.cpp
+++ b/libcxx/src/new.cpp
@@ -74,8 +74,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC
         else
 #ifndef _LIBCPP_NO_EXCEPTIONS
             throw std::bad_alloc();
+#else
+#ifdef __EMSCRIPTEN__
+            // Abort here so that when exceptions are disabled, we do not just
+            // return 0 when malloc returns 0.
+            // We could also do this with set_new_handler, but that adds a
+            // global constructor and a table entry, overhead that we can avoid
+            // by doing it this way.
+            abort();
 #else
             break;
+#endif
 #endif
     }
     return p;

diff  --git a/libcxx/src/regex.cpp b/libcxx/src/regex.cpp
index d31e494874321..fb779c540b38c 100644
--- a/libcxx/src/regex.cpp
+++ b/libcxx/src/regex.cpp
@@ -66,7 +66,7 @@ regex_error::regex_error(regex_constants::error_type ecode)
       __code_(ecode)
 {}
 
-regex_error::~regex_error() throw() {}
+regex_error::~regex_error() _NOEXCEPT {}
 
 namespace {
 

diff  --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h
index d21d3e1e2331d..3ffb1a167f388 100644
--- a/libcxxabi/include/cxxabi.h
+++ b/libcxxabi/include/cxxabi.h
@@ -39,20 +39,24 @@ extern "C"  {
 
 // 2.4.2 Allocating the Exception Object
 extern _LIBCXXABI_FUNC_VIS void *
-__cxa_allocate_exception(size_t thrown_size) throw();
+__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS void
-__cxa_free_exception(void *thrown_exception) throw();
+__cxa_free_exception(void *thrown_exception) _NOEXCEPT;
 
 // 2.4.3 Throwing the Exception Object
 extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
 __cxa_throw(void *thrown_exception, std::type_info *tinfo,
+#ifdef __USING_WASM_EXCEPTIONS__
+            void *(*dest)(void *));
+#else
             void (*dest)(void *));
+#endif
 
 // 2.5.3 Exception Handlers
 extern _LIBCXXABI_FUNC_VIS void *
-__cxa_get_exception_ptr(void *exceptionObject) throw();
+__cxa_get_exception_ptr(void *exceptionObject) _NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS void *
-__cxa_begin_catch(void *exceptionObject) throw();
+__cxa_begin_catch(void *exceptionObject) _NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch();
 #if defined(_LIBCXXABI_ARM_EHABI)
 extern _LIBCXXABI_FUNC_VIS bool
@@ -147,17 +151,17 @@ extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name,
 
 // Apple additions to support C++ 0x exception_ptr class
 // These are primitives to wrap a smart pointer around an exception object
-extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw();
+extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() _NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS void
 __cxa_rethrow_primary_exception(void *primary_exception);
 extern _LIBCXXABI_FUNC_VIS void
-__cxa_increment_exception_refcount(void *primary_exception) throw();
+__cxa_increment_exception_refcount(void *primary_exception) _NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS void
-__cxa_decrement_exception_refcount(void *primary_exception) throw();
+__cxa_decrement_exception_refcount(void *primary_exception) _NOEXCEPT;
 
 // Apple extension to support std::uncaught_exception()
-extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw();
-extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw();
+extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() _NOEXCEPT;
+extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() _NOEXCEPT;
 
 #if defined(__linux__) || defined(__Fuchsia__)
 // Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI.

diff  --git a/libcxxabi/src/abort_message.cpp b/libcxxabi/src/abort_message.cpp
index d556af1c9037d..4bb7fe37bfb6e 100644
--- a/libcxxabi/src/abort_message.cpp
+++ b/libcxxabi/src/abort_message.cpp
@@ -35,11 +35,20 @@ void abort_message(const char* format, ...)
 #ifdef __APPLE__
     fprintf(stderr, "libc++abi.dylib: ");
 #endif
+#if defined(__EMSCRIPTEN__) && defined(NDEBUG)
+    // Just trap in a non-debug build. These internal libcxxabi assertions are
+    // very rare, and it's not worth linking in vfprintf stdio support or
+    // even minimal logging for them, as we'll have a proper call stack, which
+    // will show a call into "abort_message", and can help debugging. (In a
+    // debug build that won't be inlined.)
+    __builtin_trap();
+#else
     va_list list;
     va_start(list, format);
     vfprintf(stderr, format, list);
     va_end(list);
     fprintf(stderr, "\n");
+#endif // EMSCRIPTEN
 #endif
 
 #if defined(__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H)

diff  --git a/libcxxabi/src/cxa_default_handlers.cpp b/libcxxabi/src/cxa_default_handlers.cpp
index d2f823d2b7786..de256c5a68689 100644
--- a/libcxxabi/src/cxa_default_handlers.cpp
+++ b/libcxxabi/src/cxa_default_handlers.cpp
@@ -45,6 +45,7 @@ static void demangling_terminate_handler()
                         exception_header + 1;
                 const __shim_type_info* thrown_type =
                     static_cast<const __shim_type_info*>(exception_header->exceptionType);
+#ifndef __EMSCRIPTEN__
                 // Try to get demangled name of thrown_type
                 int status;
                 char buf[1024];
@@ -52,6 +53,10 @@ static void demangling_terminate_handler()
                 const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
                 if (status != 0)
                     name = thrown_type->name();
+#else // __EMSCRIPTEN__ - we can demangle stack traces ourselves, best not to
+      //                  pull in all of libcxxabi-demangle for just this file
+                const char* name = thrown_type->name();
+#endif
                 // If the uncaught exception can be caught with std::exception&
                 const __shim_type_info* catch_type =
                     static_cast<const __shim_type_info*>(&typeid(std::exception));

diff  --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp
index ebb05ce54213d..2a7483cb4a986 100644
--- a/libcxxabi/src/cxa_exception.cpp
+++ b/libcxxabi/src/cxa_exception.cpp
@@ -180,7 +180,7 @@ extern "C" {
 //  object. Zero-fill the object. If memory can't be allocated, call
 //  std::terminate. Return a pointer to the memory to be used for the
 //  user's exception object.
-void *__cxa_allocate_exception(size_t thrown_size) throw() {
+void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT {
     size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
 
     // Allocate extra space before the __cxa_exception header to ensure the
@@ -198,7 +198,7 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() {
 
 
 //  Free a __cxa_exception object allocated with __cxa_allocate_exception.
-void __cxa_free_exception(void *thrown_object) throw() {
+void __cxa_free_exception(void *thrown_object) _NOEXCEPT {
     // Compute the size of the padding before the header.
     size_t header_offset = get_cxa_exception_offset();
     char *raw_buffer =
@@ -254,7 +254,12 @@ will call terminate, assuming that there was no handler for the
 exception.
 */
 void
+#ifdef __USING_WASM_EXCEPTIONS__
+// In wasm, destructors return their argument
+__cxa_throw(void *thrown_object, std::type_info *tinfo, void *(*dest)(void *)) {
+#else
 __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) {
+#endif
     __cxa_eh_globals *globals = __cxa_get_globals();
     __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
 
@@ -292,7 +297,7 @@ The adjusted pointer is computed by the personality routine during phase 1
 
   Requires:  exception is native
 */
-void *__cxa_get_exception_ptr(void *unwind_exception) throw() {
+void *__cxa_get_exception_ptr(void *unwind_exception) _NOEXCEPT {
 #if defined(_LIBCXXABI_ARM_EHABI)
     return reinterpret_cast<void*>(
         static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
@@ -307,7 +312,7 @@ void *__cxa_get_exception_ptr(void *unwind_exception) throw() {
 The routine to be called before the cleanup.  This will save __cxa_exception in
 __cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
 */
-bool __cxa_begin_cleanup(void *unwind_arg) throw() {
+bool __cxa_begin_cleanup(void *unwind_arg) _NOEXCEPT {
     _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
     __cxa_eh_globals* globals = __cxa_get_globals();
     __cxa_exception* exception_header =
@@ -418,7 +423,7 @@ to terminate or unexpected during unwinding.
   _Unwind_Exception and return a pointer to that.
 */
 void*
-__cxa_begin_catch(void* unwind_arg) throw()
+__cxa_begin_catch(void* unwind_arg) _NOEXCEPT
 {
     _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
     bool native_exception = __isOurExceptionClass(unwind_exception);
@@ -626,7 +631,7 @@ void __cxa_rethrow() {
     Requires:  If thrown_object is not NULL, it is a native exception.
 */
 void
-__cxa_increment_exception_refcount(void *thrown_object) throw() {
+__cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT {
     if (thrown_object != NULL )
     {
         __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
@@ -643,7 +648,7 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() {
     Requires:  If thrown_object is not NULL, it is a native exception.
 */
 _LIBCXXABI_NO_CFI
-void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
+void __cxa_decrement_exception_refcount(void *thrown_object) _NOEXCEPT {
     if (thrown_object != NULL )
     {
         __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
@@ -666,7 +671,7 @@ void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
     been no exceptions thrown, ever, on this thread, we can return NULL without
     the need to allocate the exception-handling globals.
 */
-void *__cxa_current_primary_exception() throw() {
+void *__cxa_current_primary_exception() _NOEXCEPT {
 //  get the current exception
     __cxa_eh_globals* globals = __cxa_get_globals_fast();
     if (NULL == globals)
@@ -738,10 +743,10 @@ __cxa_rethrow_primary_exception(void* thrown_object)
 }
 
 bool
-__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; }
+__cxa_uncaught_exception() _NOEXCEPT { return __cxa_uncaught_exceptions() != 0; }
 
 unsigned int
-__cxa_uncaught_exceptions() throw()
+__cxa_uncaught_exceptions() _NOEXCEPT
 {
     // This does not report foreign exceptions in flight
     __cxa_eh_globals* globals = __cxa_get_globals_fast();

diff  --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index 8c6c8bca853c6..6adc4c597792d 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -43,7 +43,12 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
 
     //  Manage the exception object itself.
     std::type_info *exceptionType;
+#ifdef __USING_WASM_EXCEPTIONS__
+    // In wasm, destructors return their argument
+    void *(*exceptionDestructor)(void *);
+#else
     void (*exceptionDestructor)(void *);
+#endif
     std::unexpected_handler unexpectedHandler;
     std::terminate_handler  terminateHandler;
 

diff  --git a/libcxxabi/src/cxa_handlers.cpp b/libcxxabi/src/cxa_handlers.cpp
index f520a4db6edac..713f02b3c6597 100644
--- a/libcxxabi/src/cxa_handlers.cpp
+++ b/libcxxabi/src/cxa_handlers.cpp
@@ -19,6 +19,32 @@
 #include "private_typeinfo.h"
 #include "include/atomic_support.h"
 
+namespace __cxxabiv1 {
+
+#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__
+// XXX EMSCRIPTEN: Copied from cxa_exception.cpp since we don't compile that
+// file in Emscripten EH mode. Note that in no-exceptions builds we include
+// cxa_noexception.cpp which provides stubs of those anyhow.
+
+//  Is it one of ours?
+uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) {
+//	On x86 and some ARM unwinders, unwind_exception->exception_class is
+//		a uint64_t. On other ARM unwinders, it is a char[8]
+//	See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
+//	So we just copy it into a uint64_t to be sure.
+	uint64_t exClass;
+	::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass));
+	return exClass;
+}
+
+bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
+    return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == 
+           (kOurExceptionClass                    & get_vendor_and_language);
+}
+#endif
+
+}
+
 namespace std
 {
 

diff  --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index f27625776111b..3715e7c7dcf08 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -22,6 +22,8 @@
 #include "private_typeinfo.h"
 #include "unwind.h"
 
+#define __USING_SJLJ_OR_WASM_EXCEPTIONS__ (__USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__)
+
 #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
 #include <windows.h>
 #include <winnt.h>
@@ -61,7 +63,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
 +------------------+--+-----+-----+------------------------+--------------------------+
 | callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table |
 +---------------------+-----------+---------------------------------------------------+
-#ifndef __USING_SJLJ_EXCEPTIONS__
+#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__
 +---------------------+-----------+------------------------------------------------+
 | Beginning of Call Site Table            The current ip lies within the           |
 | ...                                     (start, length) range of one of these    |
@@ -75,7 +77,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
 | +-------------+---------------------------------+------------------------------+ |
 | ...                                                                              |
 +----------------------------------------------------------------------------------+
-#else  // __USING_SJLJ_EXCEPTIONS__
+#else  // !__USING_SJLJ_OR_WASM_EXCEPTIONS__
 +---------------------+-----------+------------------------------------------------+
 | Beginning of Call Site Table            The current ip is a 1-based index into   |
 | ...                                     this table.  Or it is -1 meaning no      |
@@ -88,7 +90,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
 | +-------------+---------------------------------+------------------------------+ |
 | ...                                                                              |
 +----------------------------------------------------------------------------------+
-#endif  // __USING_SJLJ_EXCEPTIONS__
+#endif  // __USING_SJLJ_OR_WASM_EXCEPTIONS__
 +---------------------------------------------------------------------+
 | Beginning of Action Table       ttypeIndex == 0 : cleanup           |
 | ...                             ttypeIndex  > 0 : catch             |
@@ -529,7 +531,7 @@ void
 set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
               const scan_results& results)
 {
-#if defined(__USING_SJLJ_EXCEPTIONS__)
+#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__
 #define __builtin_eh_return_data_regno(regno) regno
 #endif
   _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
@@ -616,7 +618,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
     // Get beginning current frame's code (as defined by the
     // emitted dwarf code)
     uintptr_t funcStart = _Unwind_GetRegionStart(context);
-#ifdef __USING_SJLJ_EXCEPTIONS__
+#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__
     if (ip == uintptr_t(-1))
     {
         // no action
@@ -626,9 +628,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
     else if (ip == 0)
         call_terminate(native_exception, unwind_exception);
     // ip is 1-based index into call site table
-#else  // !__USING_SJLJ_EXCEPTIONS__
+#else  // !__USING_SJLJ_OR_WASM_EXCEPTIONS__
     uintptr_t ipOffset = ip - funcStart;
-#endif  // !defined(_USING_SLJL_EXCEPTIONS__)
+#endif  // __USING_SJLJ_OR_WASM_EXCEPTIONS__
     const uint8_t* classInfo = NULL;
     // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
     //       dwarf emission
@@ -649,8 +651,8 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
     // Walk call-site table looking for range that
     // includes current PC.
     uint8_t callSiteEncoding = *lsda++;
-#ifdef __USING_SJLJ_EXCEPTIONS__
-    (void)callSiteEncoding;  // When using SjLj exceptions, callSiteEncoding is never used
+#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__
+    (void)callSiteEncoding;  // When using SjLj/Wasm exceptions, callSiteEncoding is never used
 #endif
     uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
     const uint8_t* callSiteTableStart = lsda;
@@ -660,7 +662,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
     while (callSitePtr < callSiteTableEnd)
     {
         // There is one entry per call site.
-#ifndef __USING_SJLJ_EXCEPTIONS__
+#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__
         // The call sites are non-overlapping in [start, start+length)
         // The call sites are ordered in increasing value of start
         uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
@@ -668,15 +670,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
         uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if ((start <= ipOffset) && (ipOffset < (start + length)))
-#else  // __USING_SJLJ_EXCEPTIONS__
+#else  // __USING_SJLJ_OR_WASM_EXCEPTIONS__
         // ip is 1-based index into this table
         uintptr_t landingPad = readULEB128(&callSitePtr);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if (--ip == 0)
-#endif  // __USING_SJLJ_EXCEPTIONS__
+#endif  // !__USING_SJLJ_OR_WASM_EXCEPTIONS__
         {
             // Found the call site containing ip.
-#ifndef __USING_SJLJ_EXCEPTIONS__
+#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__
             if (landingPad == 0)
             {
                 // No handler here
@@ -684,9 +686,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
                 return;
             }
             landingPad = (uintptr_t)lpStart + landingPad;
-#else  // __USING_SJLJ_EXCEPTIONS__
+#else  // __USING_SJLJ_OR_WASM_EXCEPTIONS__
             ++landingPad;
-#endif  // __USING_SJLJ_EXCEPTIONS__
+#endif  // !__USING_SJLJ_OR_WASM_EXCEPTIONS__
             if (actionEntry == 0)
             {
                 // Found a cleanup
@@ -725,7 +727,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
                         // If this is a type 2 search save state and return _URC_HANDLER_FOUND
                         // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
                         // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
+#ifdef __USING_WASM_EXCEPTIONS__
+                        // Wasm does not do two-phase unwinding and only uses cleanup phase
+                        if (actions & _UA_CLEANUP_PHASE)
+#else
                         if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
+#endif
                         {
                             // Save state and return _URC_HANDLER_FOUND
                             results.ttypeIndex = ttypeIndex;
@@ -761,7 +768,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
                             // If this is a type 1 search save state and return _URC_HANDLER_FOUND
                             // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1!
                             // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan
+#ifdef __USING_WASM_EXCEPTIONS__
+                            // Wasm does not do two-phase unwinding and only uses cleanup phase
+                            if (actions & _UA_CLEANUP_PHASE)
+#else
                             if (actions & _UA_SEARCH_PHASE)
+#endif
                             {
                                 // Save state and return _URC_HANDLER_FOUND
                                 results.ttypeIndex = ttypeIndex;
@@ -805,7 +817,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
                             // If this is a type 1 search, save state and return _URC_HANDLER_FOUND
                             // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
                             // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
+#ifdef __USING_WASM_EXCEPTIONS__
+                            // Wasm does not do two-phase unwinding and only uses cleanup phase
+                            if (actions & _UA_CLEANUP_PHASE)
+#else
                             if (actions & _UA_SEARCH_PHASE)
+#endif
                             {
                                 // Save state and return _URC_HANDLER_FOUND
                                 results.ttypeIndex = ttypeIndex;
@@ -830,7 +847,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
                         // If this is a type 2 search, save state and return _URC_HANDLER_FOUND
                         // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
                         // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
+#ifdef __USING_WASM_EXCEPTIONS__
+                        // Wasm does not do two-phase unwinding and only uses cleanup phase
+                        if (actions & _UA_CLEANUP_PHASE)
+#else
                         if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
+#endif
                         {
                             // Save state and return _URC_HANDLER_FOUND
                             results.ttypeIndex = ttypeIndex;
@@ -878,7 +900,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
                 action += actionOffset;
             }  // there is no break out of this loop, only return
         }
-#ifndef __USING_SJLJ_EXCEPTIONS__
+#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__
         else if (ipOffset < start)
         {
             // There is no call site for this ip
@@ -886,7 +908,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
             // Possible stack corruption.
             call_terminate(native_exception, unwind_exception);
         }
-#endif  // !__USING_SJLJ_EXCEPTIONS__
+#endif  // !__USING_SJLJ_OR_WASM_EXCEPTIONS__
     }  // there might be some tricky cases which break out of this loop
 
     // It is possible that no eh table entry specify how to handle
@@ -943,7 +965,9 @@ _UA_CLEANUP_PHASE
 */
 
 #if !defined(_LIBCXXABI_ARM_EHABI)
-#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+#ifdef __USING_WASM_EXCEPTIONS__
+_Unwind_Reason_Code __gxx_personality_wasm0
+#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
 static _Unwind_Reason_Code __gxx_personality_imp
 #else
 _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
@@ -1025,6 +1049,16 @@ __gxx_personality_v0
         {
             // Found a non-catching handler.  Jump to it:
             set_registers(unwind_exception, context, results);
+#ifdef __USING_WASM_EXCEPTIONS__
+            // Wasm uses only one phase in _UA_CLEANUP_PHASE, so we should set
+            // these here.
+            __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
+            exception_header->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
+            exception_header->actionRecord = results.actionRecord;
+            exception_header->languageSpecificData = results.languageSpecificData;
+            exception_header->catchTemp = reinterpret_cast<void*>(results.landingPad);
+            exception_header->adjustedPtr = results.adjustedPtr;
+#endif
             return _URC_INSTALL_CONTEXT;
         }
         // Did not find a cleanup.  Return the results of the scan

diff  --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
index 5ce762a22bc4d..99c6fa021d377 100644
--- a/libcxxabi/src/private_typeinfo.cpp
+++ b/libcxxabi/src/private_typeinfo.cpp
@@ -1288,4 +1288,35 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info,
                                   use_strcmp);
 }
 
+// XXX EMSCRIPTEN
+
+#ifndef __USING_WASM_EXCEPTIONS__
+
+// These functions are used by the emscripten-style exception handling
+// mechanism.
+// Note that they need to be included even in the `-noexcept` build of
+// libc++abi to support the case where some parts of a project are built
+// with exception catching enabled, but at link time exception catching
+// is disabled.  In this case dependencies to these functions (and the JS
+// functions which call them) will still exist in the final build.
+extern "C" {
+
+int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, void **thrown) {
+  //std::type_info *t1 = static_cast<std::type_info*>(catchType);
+  //std::type_info *t2 = static_cast<std::type_info*>(excpType);
+  //printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown);
+
+  void *temp = *thrown;
+  int ret = catchType->can_catch(excpType, temp);
+  if (ret) *thrown = temp; // apply changes only if we are catching
+  return ret;
+}
+
+int __cxa_is_pointer_type(__shim_type_info* type) {
+  return !!dynamic_cast<__pointer_type_info*>(type);
+}
+
+}
+#endif // __USING_EMSCRIPTEN_EXCEPTIONS__
+
 }  // __cxxabiv1

diff  --git a/libcxxabi/src/stdlib_new_delete.cpp b/libcxxabi/src/stdlib_new_delete.cpp
index 698c5f7c290c0..0fcb486ec663a 100644
--- a/libcxxabi/src/stdlib_new_delete.cpp
+++ b/libcxxabi/src/stdlib_new_delete.cpp
@@ -38,8 +38,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC
         else
 #ifndef _LIBCXXABI_NO_EXCEPTIONS
             throw std::bad_alloc();
+#else
+#ifdef __EMSCRIPTEN__
+            // Abort here so that when exceptions are disabled, we do not just
+            // return 0 when malloc returns 0.
+            // We could also do this with set_new_handler, but that adds a
+            // global constructor and a table entry, overhead that we can avoid
+            // by doing it this way.
+            abort();
 #else
             break;
+#endif
 #endif
     }
     return p;


        


More information about the llvm-branch-commits mailing list