[llvm-branch-commits] [compiler-rt] 60e78c0 - Update library changes from upstream llvmorg-12.0.0
Sam Clegg via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon May 24 20:49:44 PDT 2021
Author: Sam Clegg
Date: 2021-05-24T20:49:18-07:00
New Revision: 60e78c0fb0a394b17d61e9be2a43ed1e34b31852
URL: https://github.com/llvm/llvm-project/commit/60e78c0fb0a394b17d61e9be2a43ed1e34b31852
DIFF: https://github.com/llvm/llvm-project/commit/60e78c0fb0a394b17d61e9be2a43ed1e34b31852.diff
LOG: Update library changes from upstream llvmorg-12.0.0
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/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_flags.cpp
compiler-rt/lib/ubsan/ubsan_handlers.cpp
compiler-rt/lib/ubsan/ubsan_platform.h
compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
libcxx/include/__config
libcxx/include/typeinfo
libcxx/src/include/config_elast.h
libcxx/src/new.cpp
libcxx/src/support/runtime/exception_fallback.ipp
libcxxabi/include/cxxabi.h
libcxxabi/src/abort_message.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 cb6a89fe32ce7..197dfb23661af 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().
@@ -54,7 +60,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;
@@ -115,6 +125,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
@@ -123,12 +153,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 cd07d51878b1c..6f124e9770373 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"
@@ -704,4 +704,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 9c3f0a5338ee5..7d7b3631a187c 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 f239c3ee2ff92..aa499376df64f 100644
--- a/compiler-rt/lib/asan/asan_mapping.h
+++ b/compiler-rt/lib/asan/asan_mapping.h
@@ -287,8 +287,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 44f872ef61909..15be546f62b23 100644
--- a/compiler-rt/lib/asan/asan_poisoning.cpp
+++ b/compiler-rt/lib/asan/asan_poisoning.cpp
@@ -181,6 +181,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 d7f19d846544b..6e49520498158 100644
--- a/compiler-rt/lib/asan/asan_posix.cpp
+++ b/compiler-rt/lib/asan/asan_posix.cpp
@@ -40,6 +40,9 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
}
bool PlatformUnpoisonStacks() {
+#if SANITIZER_EMSCRIPTEN
+ return false;
+#else
stack_t signal_stack;
CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));
uptr sigalt_bottom = (uptr)signal_stack.ss_sp;
@@ -63,6 +66,7 @@ bool PlatformUnpoisonStacks() {
&tls_size);
UnpoisonStack(default_bottom, default_bottom + stack_size, "default");
return true;
+#endif
}
// ---------------------- TSD ---------------- {{{1
@@ -111,7 +115,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 7b5a929963c6a..3acaa74e3f5ea 100644
--- a/compiler-rt/lib/asan/asan_rtl.cpp
+++ b/compiler-rt/lib/asan/asan_rtl.cpp
@@ -51,6 +51,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);
@@ -60,6 +61,7 @@ static void AsanDie() {
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
}
+#endif
}
static void AsanCheckFailed(const char *file, int line, const char *cond,
@@ -315,7 +317,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
@@ -464,7 +466,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 2ead4425add83..9b9e7ae3fe15f 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 19ac6c1627ca5..a15571b0e4258 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
@@ -257,7 +259,9 @@ thread_return_t AsanThread::ThreadStart(tid_t os_id) {
Init();
asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
+#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/interception/interception.h b/compiler-rt/lib/interception/interception.h
index cb0b5284ed268..c69a63963798d 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_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_SOLARIS
+ 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 a08f8cb98c409..6d3957e570267 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_SOLARIS
+ SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
# error "interception_linux.h should be included from interception library only"
diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp
index 2c0a3bf0787c2..e1e33c068e1fe 100644
--- a/compiler-rt/lib/lsan/lsan.cpp
+++ b/compiler-rt/lib/lsan/lsan.cpp
@@ -19,6 +19,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;
@@ -57,7 +62,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;
@@ -75,7 +84,22 @@ static void InitializeFlags() {
// Override from user-specified string.
const char *lsan_default_options = __lsan_default_options();
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
InitializeCommonFlags();
@@ -101,7 +125,10 @@ extern "C" void __lsan_init() {
InitTlsSize();
InitializeInterceptors();
InitializeThreadRegistry();
+#if !SANITIZER_EMSCRIPTEN
+ // Emscripten does not have signals
InstallDeadlySignalHandlers(LsanOnDeadlySignal);
+#endif
InitializeMainThread();
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp
index 70422957e6f30..5dff571e4a059 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 17e13cd014ba4..050a9143bc014 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 d5b4132b24d58..50a2e1952ecd6 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -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 {
@@ -111,7 +115,7 @@ static const char kStdSuppressions[] =
void InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
- suppression_ctx = new (suppression_placeholder)
+ suppression_ctx = new (suppression_placeholder) // NOLINT
LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
}
@@ -191,7 +195,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);
@@ -210,6 +223,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());
@@ -274,6 +295,7 @@ static void ProcessThreadRegistry(Frontier *frontier) {
}
}
+#if !SANITIZER_EMSCRIPTEN
// Scans thread data (stacks and TLS) for heap pointers.
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier) {
@@ -389,6 +411,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
// Add pointers reachable from ThreadContexts
ProcessThreadRegistry(frontier);
}
+#endif // !SANITIZER_EMSCRIPTEN
#endif // SANITIZER_FUCHSIA
@@ -406,14 +429,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.
@@ -535,6 +566,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;
@@ -542,6 +574,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.
@@ -667,7 +700,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, ¶m->frontier);
ForEachChunk(CollectLeaksCb, ¶m->leak_report);
// Clean up for subsequent leak checks. This assumes we did not overwrite any
@@ -784,8 +819,15 @@ Suppression *LeakSuppressionContext::GetSuppressionForStack(
LazyInit();
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) {
suppressed_stacks_sorted = false;
suppressed_stacks.push_back(stack_trace_id);
diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h
index b0ae6f020b63a..809e7e57a9f19 100644
--- a/compiler-rt/lib/lsan/lsan_common.h
+++ b/compiler-rt/lib/lsan/lsan_common.h
@@ -41,7 +41,7 @@
#define CAN_SANITIZE_LEAKS 1
#elif defined(__arm__) && SANITIZER_LINUX
#define CAN_SANITIZE_LEAKS 1
-#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
+#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN
#define CAN_SANITIZE_LEAKS 1
#else
#define CAN_SANITIZE_LEAKS 0
@@ -230,6 +230,10 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches);
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 3af586e220f6c..896f0479cb0a8 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 bf8d316770ee1..e90bcb50d0f3a 100644
--- a/compiler-rt/lib/lsan/lsan_interceptors.cpp
+++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp
@@ -393,6 +393,17 @@ 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);
+ int emscripten_builtin_pthread_detach(void *th);
+ 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;
@@ -428,7 +439,11 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
internal_sched_yield();
ThreadStart(tid, GetTid());
+#if SANITIZER_EMSCRIPTEN
+ emscripten_builtin_free(p);
+#else
atomic_store(&p->tid, 0, memory_order_release);
+#endif
return callback(param);
}
@@ -444,10 +459,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
@@ -455,15 +477,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);
@@ -488,6 +518,7 @@ INTERCEPTOR(int, pthread_detach, void *th) {
return res;
}
+#if !SANITIZER_EMSCRIPTEN
INTERCEPTOR(void, _exit, int status) {
if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
REAL(_exit)(status);
@@ -495,14 +526,13 @@ INTERCEPTOR(void, _exit, int status) {
#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
#include "sanitizer_common/sanitizer_signal_interceptors.inc"
-
-#endif // SANITIZER_POSIX
+#endif
namespace __lsan {
void InitializeInterceptors() {
// Fuchsia doesn't use interceptors that require any setup.
-#if !SANITIZER_FUCHSIA
+#if !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN
InitializeSignalInterceptors();
INTERCEPT_FUNCTION(malloc);
@@ -544,3 +574,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 47c2f21b5a6bc..63ae2c1a945b8 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 || SANITIZER_FUCHSIA
+#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN
#include "lsan_allocator.h"
@@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {}
} // namespace __lsan
-#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
+#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
index 192e9392d494a..650cf99128d78 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
@@ -19,12 +19,15 @@
#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_ENAMETOOLONG 36
+#define errno_ENOMEM __WASI_ERRNO_NOMEM
+#define errno_EBUSY __WASI_ERRNO_BUSY
+#define errno_EINVAL __WASI_ERRNO_INVAL
+#define errno_ENAMETOOLONG __WASI_ERRNO_NAMETOOLONG
// 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 d8f0540037d24..9e6f406029e0d 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -181,7 +181,7 @@ typedef u64 OFF64_T;
#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
typedef uptr operator_new_size_type;
#else
-# if defined(__s390__) && !defined(__s390x__)
+# if 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 379f6d9e294b7..d1738e0c2aecf 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_SOLARIS
+ SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
@@ -103,9 +103,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
+#if !SANITIZER_S390 && !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,8 +185,9 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
offset / 4096);
#endif
}
-#endif // !SANITIZER_S390
+#endif // !SANITIZER_S390 && !SANITIZER_NETBSD
+#if !SANITIZER_EMSCRIPTEN
uptr internal_munmap(void *addr, uptr length) {
return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
}
@@ -186,13 +195,18 @@ uptr internal_munmap(void *addr, uptr length) {
int internal_mprotect(void *addr, uptr length, int prot) {
return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
}
+#endif
int internal_madvise(uptr addr, uptr length, int advice) {
return internal_syscall(SYSCALL(madvise), addr, length, advice);
}
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) {
@@ -213,27 +227,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,9 +456,14 @@ 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
}
+#if !SANITIZER_EMSCRIPTEN
unsigned int internal_sleep(unsigned int seconds) {
struct timespec ts;
ts.tv_sec = seconds;
@@ -436,6 +478,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
#if !SANITIZER_NETBSD
@@ -472,11 +515,14 @@ tid_t GetTid() {
return Tid;
#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);
@@ -488,8 +534,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
timeval tv;
@@ -506,11 +553,19 @@ 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_SOLARIS
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
if (::environ != 0) {
uptr NameLen = internal_strlen(name);
for (char **Env = ::environ; *Env != 0; Env++) {
@@ -579,6 +634,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
}
#endif
+#if !SANITIZER_EMSCRIPTEN
static void GetArgsAndEnv(char ***argv, char ***envp) {
#if SANITIZER_FREEBSD
// On FreeBSD, retrieving the argument and environment arrays is done via the
@@ -630,6 +686,8 @@ char **GetEnviron() {
return envp;
}
+#endif // !SANITIZER_EMSCRIPTEN
+
#if !SANITIZER_SOLARIS
enum MutexState {
MtxUnlocked = 0,
@@ -651,6 +709,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);
@@ -667,6 +727,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
@@ -703,11 +765,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,
@@ -741,7 +805,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
@@ -750,12 +819,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));
@@ -850,6 +924,8 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset) {
#if SANITIZER_FREEBSD
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;
@@ -899,7 +975,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];
@@ -1080,19 +1156,23 @@ 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
+
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
@@ -2118,11 +2198,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 24902d1b6bcef..bb432f75aa86a 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_SOLARIS
+ 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 96c01bad870d1..79cb5a2a5deec 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(__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
@@ -117,9 +117,15 @@
# 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_SOLARIS)
+ SANITIZER_NETBSD || 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 068fc9829e57d..ee08024e06987 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
@@ -266,7 +278,7 @@
#define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX
#define SANITIZER_INTERCEPT_SYSMSG SI_LINUX_NOT_ANDROID
#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
@@ -304,7 +316,7 @@
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || 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 12dd39e674ac8..fe8b04a9c4880 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
@@ -11,7 +11,7 @@
// Sizes and layouts of platform-specific POSIX data structures.
//===----------------------------------------------------------------------===//
-#if defined(__linux__) || defined(__APPLE__)
+#if defined(__linux__) || defined(__APPLE__) || defined(__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
@@ -23,7 +23,7 @@
// Must go after undef _FILE_OFFSET_BITS.
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN
// Must go after undef _FILE_OFFSET_BITS.
#include "sanitizer_glibc_version.h"
@@ -59,7 +59,7 @@
#include <net/route.h>
#endif
-#if !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
#include <sys/mount.h>
#include <sys/timeb.h>
#include <utmpx.h>
@@ -160,7 +160,7 @@ typedef struct user_fpregs elf_fpregset_t;
#include <sys/vfs.h>
#include <sys/epoll.h>
#include <linux/capability.h>
-#else
+#elif !SANITIZER_EMSCRIPTEN
#include <fstab.h>
#endif // SANITIZER_LINUX
@@ -211,7 +211,7 @@ namespace __sanitizer {
#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
unsigned struct_fstab_sz = sizeof(struct fstab);
#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
-#if !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
unsigned struct_statfs_sz = sizeof(struct statfs);
unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
unsigned ucontext_t_sz = sizeof(ucontext_t);
@@ -403,7 +403,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);
@@ -485,15 +488,18 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
#endif // SANITIZER_GLIBC
-#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;
@@ -542,6 +548,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);
@@ -1044,6 +1051,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);
@@ -1053,6 +1061,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));
@@ -1072,6 +1081,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));
@@ -1086,6 +1096,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);
@@ -1139,7 +1150,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_GLIBC || SANITIZER_FREEBSD
CHECK_TYPE_SIZE(ipc_perm);
@@ -1177,7 +1190,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);
@@ -1207,7 +1220,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 836b178c131ba..769fe36a90f78 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"
@@ -506,7 +506,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
@@ -559,6 +559,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 2e080098283fd..fd9025882db1e 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
@@ -254,6 +264,7 @@ void DumpProcessMap() {
UnmapOrDie(filename, kBufSize);
}
#endif
+#endif
const char *GetPwd() {
return GetEnv("PWD");
@@ -274,6 +285,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);
@@ -285,6 +300,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 d29438cf9dbd5..623c9e361701a 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -211,7 +211,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);
@@ -271,6 +273,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);
@@ -290,6 +297,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) {
@@ -297,7 +305,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 b0487d8987db2..d84d9c9fba93c 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
@@ -50,9 +50,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;
@@ -63,8 +65,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 15616f899d01e..03d4d2dd1568e 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -32,7 +32,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_RTEMS
+#if SANITIZER_MAC || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN
# define SANITIZER_CAN_SLOW_UNWIND 0
#else
# define SANITIZER_CAN_SLOW_UNWIND 1
@@ -64,6 +64,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 7808ba9b0f572..d0ef5f31547fa 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
@@ -29,9 +29,15 @@ void StackTrace::Print() const {
bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format);
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;
if (symbolize)
frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
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 4dd5cc3ad7cbe..ef7635cf792b4 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 c99a6ceaa5623..1e3d16141b80a 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -40,7 +40,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);
@@ -57,7 +71,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 8829985b5b07f..ba7ed46f861cc 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_SOLARIS
+#if SANITIZER_FREEBSD || SANITIZER_MAC || 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 846cd89ee19f8..4e0c2bcf0e65f 100644
--- a/compiler-rt/lib/ubsan/ubsan_checks.inc
+++ b/compiler-rt/lib/ubsan/ubsan_checks.inc
@@ -20,11 +20,6 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use",
"nullability-assign")
-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..c8f7960db42ac 100644
--- a/compiler-rt/lib/ubsan/ubsan_diag.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_diag.cpp
@@ -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_flags.cpp b/compiler-rt/lib/ubsan/ubsan_flags.cpp
index 25cefd46ce27c..48bb217d45695 100644
--- a/compiler-rt/lib/ubsan/ubsan_flags.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_flags.cpp
@@ -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 {
static const char *GetFlag(const char *flag) {
@@ -50,7 +55,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);
}
@@ -64,7 +74,18 @@ void InitializeFlags() {
// Override from user-specified string.
parser.ParseString(__ubsan_default_options());
// Override from environment variable.
+#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.ParseStringFromEnv("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 e201e6bba2207..b070a378c0d47 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp
@@ -766,33 +766,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_platform.h b/compiler-rt/lib/ubsan/ubsan_platform.h
index 32d949d75b9c0..82efd0c3414ee 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(__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..8d980e1a26391 100644
--- a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
@@ -26,7 +26,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 +45,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/libcxx/include/__config b/libcxx/include/__config
index a3838c89e8e16..f3df1c770dfc8 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -1,3 +1,6 @@
+// XXX EMSCRIPTEN: macros that would ordinarily be added from __config_site.in
+#define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS
+
// -*- C++ -*-
//===--------------------------- __config ---------------------------------===//
//
@@ -101,7 +104,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
// Re-worked external template instantiations for std::string with a focus on
@@ -318,7 +322,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,
@@ -920,7 +924,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
@@ -1132,6 +1136,7 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container(
defined(__CloudABI__) || \
defined(__sun__) || \
defined(__MVS__) || \
+ defined(__EMSCRIPTEN__) || \
(defined(__MINGW32__) && __has_include(<pthread.h>))
# define _LIBCPP_HAS_THREAD_API_PTHREAD
# elif defined(__Fuchsia__)
diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo
index 048e57614affd..5f43b4df3b6a5 100644
--- a/libcxx/include/typeinfo
+++ b/libcxx/include/typeinfo
@@ -324,6 +324,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 3113f9fb5cd17..c5df5423ef140 100644
--- a/libcxx/src/include/config_elast.h
+++ b/libcxx/src/include/config_elast.h
@@ -33,6 +33,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/new.cpp b/libcxx/src/new.cpp
index 9d01330ba7d5f..c2faf3d92a5cc 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/support/runtime/exception_fallback.ipp b/libcxx/src/support/runtime/exception_fallback.ipp
index faa112f7f3a43..376a0381f5452 100644
--- a/libcxx/src/support/runtime/exception_fallback.ipp
+++ b/libcxx/src/support/runtime/exception_fallback.ipp
@@ -49,6 +49,7 @@ get_terminate() _NOEXCEPT
return __libcpp_atomic_load(&__terminate_handler);
}
+#ifndef __EMSCRIPTEN__ // We provide this in JS
_LIBCPP_NORETURN
void
terminate() _NOEXCEPT
@@ -71,7 +72,9 @@ terminate() _NOEXCEPT
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
+#endif // !__EMSCRIPTEN__
+#if !defined(__EMSCRIPTEN__)
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
int uncaught_exceptions() _NOEXCEPT
@@ -80,6 +83,7 @@ int uncaught_exceptions() _NOEXCEPT
fprintf(stderr, "uncaught_exceptions not yet implemented\n");
::abort();
}
+#endif // !__EMSCRIPTEN__
exception::~exception() _NOEXCEPT
diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h
index 43ce6f5f740d5..8b5368150b8e3 100644
--- a/libcxxabi/include/cxxabi.h
+++ b/libcxxabi/include/cxxabi.h
@@ -40,20 +40,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
@@ -148,17 +152,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 ad44063facb71..4aa4f71321428 100644
--- a/libcxxabi/src/abort_message.cpp
+++ b/libcxxabi/src/abort_message.cpp
@@ -33,12 +33,21 @@ void abort_message(const char* format, ...)
// formatting into the variable-sized buffer fails.
#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL)
{
+#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
fprintf(stderr, "libc++abi: ");
va_list list;
va_start(list, format);
vfprintf(stderr, format, list);
va_end(list);
fprintf(stderr, "\n");
+#endif
}
#endif
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 81aa85165dd3d..bbe5f0278b4fb 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
@@ -685,9 +687,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
}
landingPad = (uintptr_t)lpStart + landingPad;
results.landingPad = 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
@@ -714,6 +716,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
native_exception, unwind_exception);
if (catchType == 0)
{
+#error fixme
+ /*
+#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
+*/
// Found catch (...) catches everything, including
// foreign exceptions. This is search phase, cleanup
// phase with foreign exception, or forced unwinding.
@@ -741,6 +752,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
}
if (catchType->can_catch(excpType, adjustedPtr))
{
+#error fixme
+ /*
+#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
+*/
// Found a matching handler. This is either search
// phase or forced unwinding.
assert(actions &
@@ -774,10 +794,17 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
ttypeEncoding, excpType,
adjustedPtr, unwind_exception))
{
+#error fixme
+ /*
+#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
+*/
// Native exception caught by exception
// specification.
- assert(actions & _UA_SEARCH_PHASE);
- results.ttypeIndex = ttypeIndex;
results.actionRecord = actionRecord;
results.adjustedPtr = adjustedPtr;
results.reason = _URC_HANDLER_FOUND;
@@ -812,7 +839,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
@@ -820,7 +847,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
@@ -877,7 +904,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
@@ -940,6 +969,16 @@ __gxx_personality_v0
assert(actions & _UA_CLEANUP_PHASE);
assert(results.reason == _URC_HANDLER_FOUND);
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;
}
diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
index c77ad669c49e3..8072ebb7ef2d0 100644
--- a/libcxxabi/src/private_typeinfo.cpp
+++ b/libcxxabi/src/private_typeinfo.cpp
@@ -1323,4 +1323,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 8ef3057dd45e4..14370c862211b 100644
--- a/libcxxabi/src/stdlib_new_delete.cpp
+++ b/libcxxabi/src/stdlib_new_delete.cpp
@@ -37,8 +37,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