diff --git a/compiler-rt/lib/asan/asan_errors.cpp b/compiler-rt/lib/asan/asan_errors.cpp index 99d6bdac3d720e..42793787eeb531 100644 --- a/compiler-rt/lib/asan/asan_errors.cpp +++ b/compiler-rt/lib/asan/asan_errors.cpp @@ -510,6 +510,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_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp index af73d31b8a5dc3..9622881839e388 100644 --- a/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/compiler-rt/lib/asan/asan_fake_stack.cpp @@ -77,11 +77,11 @@ FakeStack* FakeStack::Create(uptr stack_size_log) { VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; " "mmapped %zdK, noreserve=%d, true_start: %p, start of first frame: " - "0x%zx\n", + "%p\n", GetCurrentTidOrInvalid(), (void*)p, (void*)(p + FakeStack::RequiredSize(stack_size_log)), stack_size_log, size >> 10, flags()->uar_noreserve, res->true_start, - res->GetFrame(stack_size_log, /*class_id*/ 0, /*pos*/ 0)); + (void*)res->GetFrame(stack_size_log, /*class_id*/ 0, /*pos*/ 0)); return res; } diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp index 190a89345dd184..16975a1bde2a61 100644 --- a/compiler-rt/lib/asan/asan_flags.cpp +++ b/compiler-rt/lib/asan/asan_flags.cpp @@ -24,6 +24,12 @@ #include "ubsan/ubsan_flags.h" #include "ubsan/ubsan_platform.h" +#if SANITIZER_EMSCRIPTEN +#include +#include "emscripten_internal.h" +#endif + + namespace __asan { Flags asan_flags_dont_use_directly; // use via flags(). @@ -70,7 +76,11 @@ static void InitializeDefaultFlags() { 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; @@ -129,6 +139,23 @@ static void InitializeDefaultFlags() { lsan_parser.ParseString(lsan_default_options); #endif +#if SANITIZER_EMSCRIPTEN + char *options; + // Override from Emscripten Module. + // TODO: add EM_ASM_I64 and avoid using a double for a 64-bit pointer. +#define MAKE_OPTION_LOAD(parser, name) \ + options = _emscripten_sanitizer_get_option(name); \ + parser.ParseString(options); \ + 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 @@ -137,9 +164,15 @@ static void InitializeDefaultFlags() { #if CAN_SANITIZE_UB ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS"); #endif +#endif // SANITIZER_EMSCRIPTEN InitializeCommonFlags(); +#if SANITIZER_EMSCRIPTEN + if (common_flags()->malloc_context_size <= 1) + StackTrace::snapshot_stack = false; +#endif // SANITIZER_EMSCRIPTEN + // // TODO(samsonov): print all of the flags (ASan, LSan, common). DisplayHelpMessages(&asan_parser); } diff --git a/compiler-rt/lib/asan/asan_globals.cpp b/compiler-rt/lib/asan/asan_globals.cpp index c83b782cb85f89..daf893c62efbff 100644 --- a/compiler-rt/lib/asan/asan_globals.cpp +++ b/compiler-rt/lib/asan/asan_globals.cpp @@ -387,6 +387,7 @@ void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g, // ---------------------- Interface ---------------- {{{1 using namespace __asan; +#if !SANITIZER_EMSCRIPTEN // Apply __asan_register_globals to all globals found in the same loaded // executable or shared library as `flag'. The flag tracks whether globals have // already been registered or not for this image. @@ -424,6 +425,7 @@ void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { __asan_unregister_globals(globals_start, globals_stop - globals_start); *flag = 0; } +#endif // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 02f0ffde72042c..cb356e1a1e3b10 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -27,10 +27,10 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_libc.h" -// There is no general interception at all on Fuchsia. +// There is no general interception at all on Fuchsia or Emscripten. // Only the functions in asan_interceptors_memintrinsics.cpp are // really defined to replace libc functions. -#if !SANITIZER_FUCHSIA +#if !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN # if SANITIZER_POSIX # include "sanitizer_common/sanitizer_posix.h" @@ -960,4 +960,4 @@ void InitializeAsanInterceptors() { } // namespace __asan -#endif // !SANITIZER_FUCHSIA +#endif // !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp index f52ae9ae8d17c8..3bc2b997420c7f 100644 --- a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp +++ b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp @@ -73,7 +73,7 @@ void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, size); } -#if SANITIZER_FUCHSIA +#if SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN // Fuchsia doesn't use sanitizer_common_interceptors.inc, but // the only things there it wants are these three. Just define them @@ -83,7 +83,7 @@ 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")]]; -#else // SANITIZER_FUCHSIA +#else // SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN #define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \ do { \ @@ -105,4 +105,4 @@ extern "C" decltype(__asan_memset) memset[[gnu::alias("__asan_memset")]]; #include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc" -#endif // SANITIZER_FUCHSIA +#endif // SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp index b54e38baf0b5f7..12f748bfe2f233 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_SOLARIS || SANITIZER_HAIKU || SANITIZER_AIX + SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU || \ + SANITIZER_AIX || SANITIZER_EMSCRIPTEN # include "asan_allocator.h" # include "asan_interceptors.h" @@ -217,4 +218,5 @@ void ReplaceSystemMalloc() { #endif // SANITIZER_ANDROID #endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || - // SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU + // SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU || + // SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h index 338324686a31d9..581cea6066571e 100644 --- a/compiler-rt/lib/asan/asan_mapping.h +++ b/compiler-rt/lib/asan/asan_mapping.h @@ -283,6 +283,8 @@ extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init. # if defined(__sparc__) && SANITIZER_WORDSIZE == 64 # include "asan_mapping_sparc64.h" +# elif SANITIZER_EMSCRIPTEN +# include "asan_mapping_emscripten.h" # else # define MEM_TO_SHADOW(mem) \ ((STRIP_MTE_TAG(mem) >> ASAN_SHADOW_SCALE) + (ASAN_SHADOW_OFFSET)) diff --git a/compiler-rt/lib/asan/asan_poisoning.cpp b/compiler-rt/lib/asan/asan_poisoning.cpp index 897a2be13e242f..ca062751bb8021 100644 --- a/compiler-rt/lib/asan/asan_poisoning.cpp +++ b/compiler-rt/lib/asan/asan_poisoning.cpp @@ -242,6 +242,15 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) { if (!size) return 0; uptr end = beg + size; +#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)) diff --git a/compiler-rt/lib/asan/asan_poisoning.h b/compiler-rt/lib/asan/asan_poisoning.h index 4b2d6220b1b147..a9ef26fe2b9684 100644 --- a/compiler-rt/lib/asan/asan_poisoning.h +++ b/compiler-rt/lib/asan/asan_poisoning.h @@ -67,6 +67,10 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, // probably provide higher-level interface for these operations. // For now, just memset on Windows. if (value || SANITIZER_WINDOWS == 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 598a55d89bdd22..8efd87029fb09c 100644 --- a/compiler-rt/lib/asan/asan_posix.cpp +++ b/compiler-rt/lib/asan/asan_posix.cpp @@ -41,6 +41,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; @@ -64,6 +67,7 @@ bool PlatformUnpoisonStacks() { &tls_end); UnpoisonStack(stack_begin, stack_end, "default"); return true; +#endif } // ---------------------- TSD ---------------- {{{1 diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp index b9ba250f5bcd73..f96ee2c47ce69d 100644 --- a/compiler-rt/lib/asan/asan_rtl.cpp +++ b/compiler-rt/lib/asan/asan_rtl.cpp @@ -54,6 +54,7 @@ static void AsanDie() { WaitForDebugger(flags()->sleep_before_dying, "before dying"); +#if !SANITIZER_EMSCRIPTEN if (flags()->unmap_shadow_on_exit) { if (kMidMemBeg) { UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg); @@ -63,6 +64,7 @@ static void AsanDie() { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } +#endif } static void CheckUnwind() { @@ -324,6 +326,7 @@ static void asan_atexit() { } static void InitializeHighMemEnd() { +#if !SANITIZER_EMSCRIPTEN #if !ASAN_FIXED_MAPPING kHighMemEnd = GetMaxUserVirtualAddress(); // Increase kHighMemEnd to make sure it's properly @@ -331,6 +334,7 @@ static void InitializeHighMemEnd() { kHighMemEnd |= (GetMmapGranularity() << ASAN_SHADOW_SCALE) - 1; #endif // !ASAN_FIXED_MAPPING CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); +#endif // !SANITIZER_EMSCRIPTEN } void PrintAddressSpaceLayout() { @@ -476,6 +480,7 @@ static bool AsanInitInternal() { ReplaceSystemMalloc(); +#if !SANITIZER_EMSCRIPTEN DisableCoreDumperIfNecessary(); #if SANITIZER_POSIX @@ -489,11 +494,14 @@ static bool AsanInitInternal() { // issues. } #endif // SANITIZER_POSIX +#endif // !SANITIZER_EMSCRIPTEN 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 5b3591da067bdc..8084530e53499b 100644 --- a/compiler-rt/lib/asan/asan_shadow_setup.cpp +++ b/compiler-rt/lib/asan/asan_shadow_setup.cpp @@ -13,8 +13,9 @@ #include "sanitizer_common/sanitizer_platform.h" -// asan_fuchsia.cpp has their own InitializeShadowMemory implementation. -#if !SANITIZER_FUCHSIA +// asan_fuchsia.cpp and asan_emscripten.cc have have their own +// InitializeShadowMemory implementation. +#if !SANITIZER_FUCHSIA && !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 32ab723e890013..caaf587927b374 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -131,8 +131,10 @@ void AsanThread::Destroy() { if (AsanThread *thread = GetCurrentThread()) CHECK_EQ(this, thread); malloc_storage().CommitBack(); +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack(); +#endif FlushToDeadThreadStats(&stats_); // We also clear the shadow on thread destruction because // some code may still be executing in later TSD destructors @@ -287,8 +289,10 @@ void AsanThread::ThreadStart(ThreadID os_id) { Init(); asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); +#endif } AsanThread *CreateMainThread() { @@ -578,6 +582,12 @@ void PrintThreads() { } // namespace __lsan +namespace __sanitizer { +ThreadRegistry *GetThreadRegistryLocked() { + return __lsan::GetAsanThreadRegistryLocked(); +} +} // namespace __sanitizer + // ---------------------- Interface ---------------- {{{1 using namespace __asan; diff --git a/compiler-rt/lib/builtins/atomic.c b/compiler-rt/lib/builtins/atomic.c index aded25d9baa98b..01fe8c77945e71 100644 --- a/compiler-rt/lib/builtins/atomic.c +++ b/compiler-rt/lib/builtins/atomic.c @@ -185,7 +185,7 @@ bool __atomic_is_lock_free_c(size_t size, void *ptr) { /// An atomic load operation. This is atomic with respect to the source /// pointer only. -void __atomic_load_c(int size, void *src, void *dest, int model) { +void __atomic_load_c(size_t size, void *src, void *dest, int model) { #define LOCK_FREE_ACTION(type) \ *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model); \ return; @@ -199,7 +199,7 @@ void __atomic_load_c(int size, void *src, void *dest, int model) { /// An atomic store operation. This is atomic with respect to the destination /// pointer only. -void __atomic_store_c(int size, void *dest, void *src, int model) { +void __atomic_store_c(size_t size, void *dest, void *src, int model) { #define LOCK_FREE_ACTION(type) \ __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ return; @@ -216,7 +216,7 @@ void __atomic_store_c(int size, void *dest, void *src, int model) { /// they are not, then this stores the current value from *ptr in *expected. /// /// This function returns 1 if the exchange takes place or 0 if it fails. -int __atomic_compare_exchange_c(int size, void *ptr, void *expected, +int __atomic_compare_exchange_c(size_t size, void *ptr, void *expected, void *desired, int success, int failure) { #define LOCK_FREE_ACTION(type) \ return __c11_atomic_compare_exchange_strong( \ @@ -238,7 +238,7 @@ int __atomic_compare_exchange_c(int size, void *ptr, void *expected, /// Performs an atomic exchange operation between two pointers. This is atomic /// with respect to the target address. -void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { +void __atomic_exchange_c(size_t size, void *ptr, void *val, void *old, int model) { #define LOCK_FREE_ACTION(type) \ *(type *)old = \ __c11_atomic_exchange((_Atomic(type) *)ptr, *(type *)val, model); \ diff --git a/compiler-rt/lib/builtins/fp_compare_impl.inc b/compiler-rt/lib/builtins/fp_compare_impl.inc index f883338c471d35..fa1629fc1a07a9 100644 --- a/compiler-rt/lib/builtins/fp_compare_impl.inc +++ b/compiler-rt/lib/builtins/fp_compare_impl.inc @@ -12,7 +12,7 @@ // functions. We need to ensure that the return value is sign-extended in the // same way as GCC expects (since otherwise GCC-generated __builtin_isinf // returns true for finite 128-bit floating-point numbers). -#if defined(__aarch64__) || defined(__arm64ec__) +#if defined(__aarch64__) || defined(__arm64ec__) || defined(__wasm__) // AArch64 GCC overrides libgcc_cmp_return to use int instead of long. typedef int CMP_RESULT; #elif __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 4 diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h index 9fe7d3db308bff..b33d38effc9ac3 100644 --- a/compiler-rt/lib/interception/interception.h +++ b/compiler-rt/lib/interception/interception.h @@ -19,7 +19,8 @@ #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_APPLE && \ !SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \ - !SANITIZER_SOLARIS && !SANITIZER_HAIKU && !SANITIZER_AIX + !SANITIZER_SOLARIS && !SANITIZER_HAIKU && !SANITIZER_AIX && \ + !SANITIZER_EMSCRIPTEN # error "Interception doesn't work on this operating system." #endif @@ -178,6 +179,10 @@ const interpose_substitution substitution_##func_name[] \ # define DECLARE_WRAPPER(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__) \ __attribute__((alias("__interceptor_" #func), visibility("default"))); +#elif SANITIZER_EMSCRIPTEN +# define WRAP(x) x +# define INTERCEPTOR_ATTRIBUTE +# define DECLARE_WRAPPER(ret_type, func, ...) #elif !SANITIZER_FUCHSIA // LINUX, FREEBSD, NETBSD, SOLARIS # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) # if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT @@ -261,6 +266,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_APPLE # define PTR_TO_REAL(x) real_##x # define REAL(x) __interception::PTR_TO_REAL(x) @@ -299,7 +311,7 @@ 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_APPLE && !SANITIZER_FUCHSIA +#if !SANITIZER_APPLE && !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN # define DEFINE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ @@ -383,7 +395,7 @@ inline void DoesNotSupportStaticLinking() {} # define INTERCEPT_FUNCTION_VER(func, symver) INTERCEPT_FUNCTION_AIX(func) #elif SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS || SANITIZER_HAIKU + SANITIZER_SOLARIS || SANITIZER_HAIKU || 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 0958ffe3fecc16..9a6b3ba567e00b 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_HAIKU + SANITIZER_SOLARIS || SANITIZER_HAIKU || SANITIZER_EMSCRIPTEN #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) # error interception_linux.h should be included from interception library only @@ -52,4 +52,4 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, #endif // INTERCEPTION_LINUX_H #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || - // SANITIZER_SOLARIS || SANITIZER_HAIKU + // SANITIZER_SOLARIS || SANITIZER_HAIKU || SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp index 798294b499e2f0..f7433f483b951e 100644 --- a/compiler-rt/lib/lsan/lsan.cpp +++ b/compiler-rt/lib/lsan/lsan.cpp @@ -20,6 +20,11 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_interface_internal.h" +#if SANITIZER_EMSCRIPTEN +#include "emscripten_internal.h" +#include +#endif + bool lsan_inited; bool lsan_init_is_running; @@ -54,7 +59,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; @@ -72,7 +81,18 @@ 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 = _emscripten_sanitizer_get_option("LSAN_OPTIONS"); + parser.ParseString(options); + 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(); @@ -98,7 +118,10 @@ extern "C" void __lsan_init() { ReplaceSystemMalloc(); InitializeInterceptors(); InitializeThreads(); +#if !SANITIZER_EMSCRIPTEN + // Emscripten does not have signals InstallDeadlySignalHandlers(LsanOnDeadlySignal); +#endif InitializeMainThread(); InstallAtExitCheckLeaks(); InstallAtForkHandler(); diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp index a436d9c07ac6c4..e14bee6b69b08c 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -26,9 +26,9 @@ 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 = 1ULL << 30; -#elif defined(__mips64) || defined(__aarch64__) +#elif defined(__mips64) || defined(__aarch64__) || defined(__wasm64__) static const uptr kMaxAllowedMallocSize = 4ULL << 30; #else static const uptr kMaxAllowedMallocSize = 1ULL << 40; diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp index 39537b67b681d0..120a1d959b5657 100644 --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -25,6 +25,11 @@ #include "sanitizer_common/sanitizer_thread_registry.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" +#if SANITIZER_EMSCRIPTEN +#include "lsan/lsan_allocator.h" +#include "emscripten/heap.h" +#endif + #if CAN_SANITIZE_LEAKS # if SANITIZER_APPLE @@ -129,7 +134,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)); } @@ -206,6 +211,14 @@ static inline void *TransformPointer(void *p) { // valid before reporting chunks as leaked. bool LeakSuppressionContext::SuppressInvalid(const StackTrace &stack) { uptr caller_pc = GetCallerPC(stack); +#if SANITIZER_EMSCRIPTEN + // caller_pr will always be 0 if we use malloc_context_size=0 (or 1) which + // we recommend under emscripten to save memory. It seems that this setting + // now (inadvertently?) suppreses all leaks. + // See https://reviews.llvm.org/D115319#3526676. + if (!caller_pc) + return false; +#endif // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark // it as reachable, as we can't properly report its allocation stack anyway. return !caller_pc || @@ -335,7 +348,16 @@ void ScanForPointers(uptr begin, uptr end, Frontier *frontier, 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 = accessor.LoadPtr(pp); # if SANITIZER_APPLE p = TransformPointer(p); @@ -362,6 +384,14 @@ void ScanForPointers(uptr begin, uptr end, Frontier *frontier, 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", + (void*)pp, (void*)cache_begin, (void*)cache_end); + continue; + } +#endif + m.set_tag(tag); LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", (void *)pp, p, (void *)chunk, @@ -423,6 +453,9 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls( pid_t, void (*cb)(void *, void *, uptr, void *), void *); # endif +#if SANITIZER_EMSCRIPTEN +void ProcessThreads(SuspendedThreadsList const &, Frontier *, ThreadID, uptr); +#else static void ProcessThreadRegistry(Frontier *frontier) { InternalMmapVector ptrs; GetAdditionalThreadContextPtrsLocked(&ptrs); @@ -607,6 +640,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, // Add pointers reachable from ThreadContexts ProcessThreadRegistry(frontier); } +#endif // !SANITIZER_EMSCRIPTEN # endif // SANITIZER_FUCHSIA @@ -649,12 +683,16 @@ void ScanRootRegions(Frontier *frontier, static void ProcessRootRegions(Frontier *frontier) { if (!flags()->use_root_regions || !HasRootRegions()) return; + InternalMmapVector mapped_regions; +#if SANITIZER_EMSCRIPTEN + mapped_regions.push_back({0, emscripten_get_heap_size()}); +#else MemoryMappingLayout proc_maps(/*cache_enabled*/ true); MemoryMappedSegment segment; - InternalMmapVector mapped_regions; while (proc_maps.Next(&segment)) if (segment.IsReadable()) mapped_regions.push_back({segment.start, segment.end}); +#endif // SANITIZER_EMSCRIPTEN ScanRootRegions(frontier, mapped_regions); } @@ -778,7 +816,7 @@ void LeakSuppressionContext::PrintMatchedSuppressions() { Printf("%s\n\n", line); } -# if SANITIZER_FUCHSIA +# if SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN // Fuchsia provides a libc interface that guarantees all threads are // covered, and SuspendedThreadList is never really used. @@ -786,7 +824,7 @@ static bool ReportUnsuspendedThreads(const SuspendedThreadsList &) { return true; } -# else // !SANITIZER_FUCHSIA +# else // !(SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN) static bool ReportUnsuspendedThreads( const SuspendedThreadsList &suspended_threads) { diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h index 39530c2e027faf..8b66a82e7d5e70 100644 --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -48,7 +48,7 @@ # define CAN_SANITIZE_LEAKS 1 #elif SANITIZER_RISCV64 && 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 diff --git a/compiler-rt/lib/lsan/lsan_common_linux.cpp b/compiler-rt/lib/lsan/lsan_common_linux.cpp index 6fd54bbea3c722..4fa5f5140289df 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 #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 5340c6ffba607b..836fcb5b473ee9 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -31,6 +31,18 @@ #include "lsan_common.h" #include "lsan_thread.h" +#if SANITIZER_EMSCRIPTEN +#define __ATTRP_C11_THREAD ((void*)(uptr)-1) +#include +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_pthread_exit(void *th); +} +#endif + #include using namespace __lsan; @@ -472,6 +484,14 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, ENSURE_LSAN_INITED; EnsureMainThreadIDIsCorrect(); +#if SANITIZER_EMSCRIPTEN + // In Emscripten sanitizer, attr can be nonzero but __ATTRP_C11_THREAD in case + // of C11 threads, in which case we need to run pthread_attr_init as well, so + // we treat __ATTRP_C11_THREAD like the nullptr in this function. + if (attr == __ATTRP_C11_THREAD) + attr = nullptr; +#endif + bool detached = [attr]() { int d = 0; return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d); @@ -558,6 +578,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, DEFINE_INTERNAL_PTHREAD_FUNCTIONS +#if !SANITIZER_EMSCRIPTEN INTERCEPTOR(void, _exit, int status) { if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; REAL(_exit)(status); @@ -566,14 +587,14 @@ INTERCEPTOR(void, _exit, int status) { #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #define SIGNAL_INTERCEPTOR_ENTER() ENSURE_LSAN_INITED #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_EMSCRIPTEN __interception::DoesNotSupportStaticLinking(); InitializeSignalInterceptors(); @@ -609,6 +630,7 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK; LSAN_MAYBE_INTERCEPT_STRERROR; +#endif // !SANITIZER_EMSCRIPTEN #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { @@ -621,3 +643,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 5074cee1296a81..26aaf190ce8735 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" # include "lsan_thread.h" @@ -30,4 +30,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/lsan/lsan_thread.cpp b/compiler-rt/lib/lsan/lsan_thread.cpp index 22eb9ee7680fbf..311179314938b9 100644 --- a/compiler-rt/lib/lsan/lsan_thread.cpp +++ b/compiler-rt/lib/lsan/lsan_thread.cpp @@ -46,7 +46,10 @@ void InitializeThreads() { thread_arg_retval = new (thread_arg_retval_placeholder) ThreadArgRetval(); } -ThreadArgRetval &GetThreadArgRetval() { return *thread_arg_retval; } +ThreadArgRetval &GetThreadArgRetval() { + ENSURE_LSAN_INITED; + return *thread_arg_retval; +} ThreadContextLsanBase::ThreadContextLsanBase(int tid) : ThreadContextBase(tid) {} @@ -121,3 +124,9 @@ void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { } } // namespace __lsan + +namespace __sanitizer { +ThreadRegistry *GetThreadRegistryLocked() { + return __lsan::GetLsanThreadRegistryLocked(); +} +} // namespace __sanitizer diff --git a/compiler-rt/lib/profile/InstrProfilingPort.h b/compiler-rt/lib/profile/InstrProfilingPort.h index 0149c7aacb2da0..d238cc8c3ea519 100644 --- a/compiler-rt/lib/profile/InstrProfilingPort.h +++ b/compiler-rt/lib/profile/InstrProfilingPort.h @@ -54,7 +54,7 @@ #endif #define COMPILER_RT_MAX_HOSTLEN 128 -#if defined(__ORBIS__) || defined(__wasi__) +#if defined(__ORBIS__) || defined(__wasi__) || defined(__EMSCRIPTEN__) #define COMPILER_RT_GETHOSTNAME(Name, Len) ((void)(Name), (void)(Len), (-1)) #else #define COMPILER_RT_GETHOSTNAME(Name, Len) lprofGetHostName(Name, Len) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp index f275e81ff04169..7015bfd44ccaec 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp @@ -81,6 +81,7 @@ void *BackgroundThread(void *arg) { } } +#if !SANITIZER_EMSCRIPTEN void MaybeStartBackgroudThread() { // Need to implement/test on other platforms. // Start the background thread if one of the rss limits is given. @@ -117,6 +118,7 @@ static struct BackgroudThreadStarted { #else void MaybeStartBackgroudThread() {} #endif +#endif void WriteToSyslog(const char *msg) { if (!msg) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h index 10a98a9b4e4d26..d92194fdced295 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h @@ -19,6 +19,9 @@ #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 + namespace __sanitizer { #ifdef __HAIKU__ @@ -29,12 +32,12 @@ namespace __sanitizer { # define errno_ENAMETOOLONG (0x80000000 + 0x6004) # define errno_ENOSYS (0x80007009) #else -# define errno_ENOMEM 12 -# define errno_EBUSY 16 -# define errno_EINVAL 22 -# define errno_ERANGE 34 -# define errno_ENAMETOOLONG 36 -# define errno_ENOSYS 38 +# define errno_ENOMEM __WASI_ERRNO_NOMEM +# define errno_EBUSY __WASI_ERRNO_BUSY +# define errno_EINVAL __WASI_ERRNO_INVAL +# define errno_ERANGE __WASI_ERRNO_RANGE +# define errno_ENAMETOOLONG __WASI_ERRNO_NAMETOOLONG +# define errno_ENOSYS __WASI_ERRNO_NOSYS #endif // Those might not present or their value differ on different platforms. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h b/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h index dccdee4da2bd02..c0e2f1d8ca24f8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h @@ -189,8 +189,8 @@ class FlagParser { }; template -static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, - T *var) { +void RegisterFlag(FlagParser *parser, const char *name, const char *desc, + T *var) { FlagHandler *fh = new (GetGlobalLowLevelAllocator()) FlagHandler(var); parser->RegisterHandler(name, fh, desc); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index b73b84c290086b..f65085ffcc564d 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_HAIKU + SANITIZER_SOLARIS || SANITIZER_HAIKU || SANITIZER_EMSCRIPTEN # include "sanitizer_common.h" # include "sanitizer_flags.h" @@ -63,7 +63,7 @@ # include # include # include -# if !SANITIZER_SOLARIS && !SANITIZER_HAIKU +# if !SANITIZER_SOLARIS && !SANITIZER_HAIKU && !SANITIZER_EMSCRIPTEN # include # endif # include @@ -133,6 +133,11 @@ extern struct ps_strings *__ps_strings; extern "C" char **__libc_argv; # endif +# if SANITIZER_EMSCRIPTEN +# include // For INFINITY +# include // For emscripten_futex_wait +# endif + extern char **environ; # if SANITIZER_LINUX @@ -261,7 +266,8 @@ ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); } # endif // --------------- sanitizer_libc.h -# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU +# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU && \ + !SANITIZER_EMSCRIPTEN # if !SANITIZER_S390 uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset) { @@ -344,7 +350,8 @@ uptr internal_ftruncate(fd_t fd, uptr size) { 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; @@ -606,9 +613,10 @@ uptr internal_execve(const char *filename, char *const argv[], return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, (uptr)envp); } -# endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU +# endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU && + // !SANITIZER_EMSCRIPTEN -# if !SANITIZER_NETBSD && !SANITIZER_HAIKU +# if !SANITIZER_NETBSD && !SANITIZER_HAIKU && !SANITIZER_EMSCRIPTEN void internal__exit(int exitcode) { # if SANITIZER_FREEBSD || SANITIZER_SOLARIS internal_syscall(SYSCALL(exit), exitcode); @@ -617,7 +625,7 @@ void internal__exit(int exitcode) { # endif Die(); // Unreachable. } -# endif // !SANITIZER_NETBSD && !SANITIZER_HAIKU +# endif // !SANITIZER_NETBSD && !SANITIZER_HAIKU && !SANITIZER_EMSCRIPTEN // ----------------- sanitizer_common.h bool FileExists(const char *filename) { @@ -637,7 +645,7 @@ bool DirExists(const char *path) { return S_ISDIR(st.st_mode); } -# if !SANITIZER_NETBSD +# if !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN ThreadID GetTid() { # if SANITIZER_FREEBSD long Tid; @@ -652,20 +660,22 @@ ThreadID GetTid() { # endif } +# if !SANITIZER_EMSCRIPTEN int TgKill(pid_t pid, ThreadID tid, int sig) { -# if SANITIZER_LINUX +# if SANITIZER_LINUX return internal_syscall(SYSCALL(tgkill), pid, tid, sig); -# elif SANITIZER_FREEBSD +# elif SANITIZER_FREEBSD return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig); -# elif SANITIZER_SOLARIS +# elif SANITIZER_SOLARIS (void)pid; errno = thr_kill(tid, sig); // TgKill is expected to return -1 on error, not an errno. return errno != 0 ? -1 : 0; -# elif SANITIZER_HAIKU +# elif SANITIZER_HAIKU return kill_thread(tid); -# endif +# endif } +# endif # endif # if SANITIZER_GLIBC @@ -692,7 +702,7 @@ u64 NanoTime() { // should be called first inside __asan_init. const char *GetEnv(const char *name) { # if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS || \ - SANITIZER_HAIKU + SANITIZER_HAIKU || SANITIZER_EMSCRIPTEN if (::environ != 0) { uptr NameLen = internal_strlen(name); for (char **Env = ::environ; *Env != 0; Env++) { @@ -737,7 +747,8 @@ SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; } # endif -# if !SANITIZER_HAIKU && !SANITIZER_FREEBSD && !SANITIZER_NETBSD +# if !SANITIZER_HAIKU && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \ + !SANITIZER_EMSCRIPTEN static void ReadNullSepFileToArray(const char *path, char ***arr, int arr_size) { char *buff; @@ -763,11 +774,12 @@ static void ReadNullSepFileToArray(const char *path, char ***arr, } # endif +# if !SANITIZER_EMSCRIPTEN static void GetArgsAndEnv(char ***argv, char ***envp) { -# if SANITIZER_HAIKU +# if SANITIZER_HAIKU *argv = __libc_argv; *envp = environ; -# elif SANITIZER_FREEBSD +# elif SANITIZER_FREEBSD // On FreeBSD, retrieving the argument and environment arrays is done via the // kern.ps_strings sysctl, which returns a pointer to a structure containing // this information. See also . @@ -779,11 +791,11 @@ static void GetArgsAndEnv(char ***argv, char ***envp) { } *argv = pss->ps_argvstr; *envp = pss->ps_envstr; -# elif SANITIZER_NETBSD +# elif SANITIZER_NETBSD *argv = __ps_strings->ps_argvstr; *envp = __ps_strings->ps_envstr; -# else // SANITIZER_FREEBSD -# if !SANITIZER_GO +# else // SANITIZER_FREEBSD +# if !SANITIZER_GO if (&__libc_stack_end) { uptr *stack_end = (uptr *)__libc_stack_end; // Linux/sparc64 needs an adjustment, cf. glibc @@ -800,14 +812,14 @@ static void GetArgsAndEnv(char ***argv, char ***envp) { *argv = (char **)(stack_end + 1); *envp = (char **)(stack_end + argc + 2); } else { -# endif // !SANITIZER_GO +# endif // !SANITIZER_GO static const int kMaxArgv = 2000, kMaxEnvp = 2000; ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); -# if !SANITIZER_GO +# if !SANITIZER_GO } -# endif // !SANITIZER_GO -# endif // SANITIZER_HAIKU +# endif // !SANITIZER_GO +# endif // SANITIZER_FREEBSD } char **GetArgv() { @@ -822,12 +834,16 @@ char **GetEnviron() { return envp; } +# endif // !SANITIZER_EMSCRIPTEN + # if !SANITIZER_SOLARIS void FutexWait(atomic_uint32_t *p, u32 cmp) { # if SANITIZER_FREEBSD _umtx_op(p, UMTX_OP_WAIT_UINT, cmp, 0, 0); # elif SANITIZER_NETBSD || SANITIZER_HAIKU sched_yield(); /* No userspace futex-like synchronization */ +# elif SANITIZER_EMSCRIPTEN + emscripten_futex_wait(p, cmp, INFINITY); # else internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAIT_PRIVATE, cmp, 0, 0, 0); # endif @@ -838,6 +854,8 @@ void FutexWake(atomic_uint32_t *p, u32 count) { _umtx_op(p, UMTX_OP_WAKE, count, 0, 0); # elif SANITIZER_NETBSD || SANITIZER_HAIKU /* No userspace futex-like synchronization */ +# elif SANITIZER_EMSCRIPTEN + emscripten_futex_wake(p, count); # else internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAKE_PRIVATE, count, 0, 0, 0); # endif @@ -868,7 +886,8 @@ struct linux_dirent { }; # endif -# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU +# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU && \ + !SANITIZER_EMSCRIPTEN // Syscall wrappers. uptr internal_ptrace(int request, int pid, void *addr, void *data) { return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, @@ -1080,9 +1099,9 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { return sigismember(rset, signum); } # endif -# endif // !SANITIZER_SOLARIS +# endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN -# if !SANITIZER_NETBSD && !SANITIZER_HAIKU +# if !SANITIZER_NETBSD && !SANITIZER_HAIKU && !SANITIZER_EMSCRIPTEN // ThreadLister implementation. ThreadLister::ThreadLister(pid_t pid) : buffer_(4096) { task_path_.AppendF("/proc/%d/task", pid); @@ -1285,6 +1304,10 @@ uptr GetPageSize() { } # endif +# if SANITIZER_EMSCRIPTEN +extern "C" void _emscripten_get_progname(char *buf, int buf_len); +# endif + uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { # if SANITIZER_HAIKU int32 cookie = 0; @@ -1302,6 +1325,9 @@ uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { 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 + _emscripten_get_progname(buf, buf_len); + return internal_strlen(buf); # else # if SANITIZER_FREEBSD || SANITIZER_NETBSD # if SANITIZER_FREEBSD @@ -1926,7 +1952,7 @@ HandleSignalMode GetHandleSignalMode(int signum) { return result; } -# if !SANITIZER_GO +# if !SANITIZER_GO && !SANITIZER_EMSCRIPTEN void *internal_start_thread(void *(*func)(void *arg), void *arg) { if (&internal_pthread_create == 0) return nullptr; @@ -2727,6 +2753,9 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.__pc; *bp = ucontext->uc_mcontext.__gregs[22]; *sp = ucontext->uc_mcontext.__gregs[3]; +# 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 e621799c4bdf93..482110bcf1b80d 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_HAIKU + SANITIZER_SOLARIS || SANITIZER_HAIKU || 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_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp index 530ff90c4cd16e..6ee31595372ca3 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -951,6 +951,7 @@ u64 MonotonicNanoTime() { } # endif // SANITIZER_GLIBC && !SANITIZER_GO +#if !SANITIZER_EMSCRIPTEN void ReExec() { const char *pathname = "/proc/self/exe"; @@ -989,6 +990,7 @@ void ReExec() { Printf("execve failed, errno %d\n", rverrno); Die(); } +#endif void UnmapFromTo(uptr from, uptr to) { if (to == from) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index acd2da26117c38..144d8b9949c091 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -14,8 +14,7 @@ #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \ - !(defined(__sun__) && defined(__svr4__)) && !defined(__HAIKU__) && \ - !defined(__wasi__) + !(defined(__sun__) && defined(__svr4__)) && !defined(__EMSCRIPTEN__) # error "This operating system is not supported" #endif @@ -149,9 +148,16 @@ # define SANITIZER_MUSL 0 #endif -#define SANITIZER_POSIX \ - (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_APPLE || \ - SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU) +#if defined(__EMSCRIPTEN__) +# define SANITIZER_EMSCRIPTEN 1 +#else +# define SANITIZER_EMSCRIPTEN 0 +#endif + +#define SANITIZER_POSIX \ + (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_APPLE || \ + SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU || \ + SANITIZER_EMSCRIPTEN) #if __LP64__ || defined(_WIN64) # define SANITIZER_WORDSIZE 64 @@ -311,7 +317,7 @@ # if (SANITIZER_RISCV64 && !SANITIZER_FUCHSIA && !SANITIZER_LINUX) || \ SANITIZER_IOS || SANITIZER_DRIVERKIT # define SANITIZER_CAN_USE_ALLOCATOR64 0 -# elif defined(__mips64) || defined(__hexagon__) +# elif defined(__mips64) || defined(__hexagon__) || defined(__wasm__) # define SANITIZER_CAN_USE_ALLOCATOR64 0 # else # define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64) @@ -359,6 +365,8 @@ # endif #elif defined(__sparc__) # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 52) +#elif SANITIZER_EMSCRIPTEN +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 34) #else # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47) #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 1b300bc7533b6f..5153a559860860 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -159,12 +159,24 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #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 @@ -310,7 +322,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #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_NOT_EMSCRIPTEN #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX #define SANITIZER_INTERCEPT_READDIR SI_POSIX @@ -351,7 +363,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY \ (SI_LINUX_NOT_ANDROID || SI_FREEBSD) #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 \ @@ -538,9 +550,9 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) #define SANITIZER_INTERCEPT_MMAP SI_POSIX -#define SANITIZER_INTERCEPT_MMAP64 SI_GLIBC || SI_SOLARIS +#define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ - (SI_GLIBC || SI_ANDROID || SI_FUCHSIA) + (SI_GLIBC || SI_ANDROID || SI_FUCHSIA || SI_EMSCRIPTEN) #define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) #define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC #define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID) 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 0109df531e88cd..0fa1cbb7099a75 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 @@ -24,7 +24,8 @@ // Must go after undef _FILE_OFFSET_BITS. #include "sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU +#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU || \ + SANITIZER_EMSCRIPTEN // Must go after undef _FILE_OFFSET_BITS. #include "sanitizer_glibc_version.h" @@ -60,7 +61,7 @@ #include #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN #if !SANITIZER_HAIKU #include #endif @@ -166,7 +167,7 @@ typedef struct user_fpregs elf_fpregset_t; #include #include #include -#elif !SANITIZER_HAIKU +#elif !SANITIZER_HAIKU && !SANITIZER_EMSCRIPTEN #include #endif // SANITIZER_LINUX @@ -225,7 +226,7 @@ namespace __sanitizer { unsigned struct_fstab_sz = sizeof(struct fstab); #endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || // SANITIZER_APPLE -#if !SANITIZER_ANDROID && !SANITIZER_HAIKU +#if !SANITIZER_ANDROID && !SANITIZER_HAIKU && !SANITIZER_EMSCRIPTEN unsigned struct_statfs_sz = sizeof(struct statfs); unsigned struct_sockaddr_sz = sizeof(struct sockaddr); @@ -466,7 +467,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); @@ -543,17 +547,21 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_sock_fprog_sz = sizeof(struct sock_fprog); # endif // SANITIZER_GLIBC -# if !SANITIZER_ANDROID && !SANITIZER_APPLE && !SANITIZER_HAIKU +# if !SANITIZER_ANDROID && !SANITIZER_APPLE && !SANITIZER_HAIKU && \ + !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 unsigned fpos_t_sz = sizeof(fpos_t); +#if !SANITIZER_EMSCRIPTEN const unsigned long __sanitizer_bufsiz = BUFSIZ; +#endif const unsigned IOCTL_NOT_PRESENT = 0; +#if !SANITIZER_EMSCRIPTEN unsigned IOCTL_FIONBIO = FIONBIO; #if !SANITIZER_HAIKU unsigned IOCTL_FIOASYNC = FIOASYNC; @@ -608,6 +616,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); @@ -1109,6 +1118,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_APPLE CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); @@ -1118,6 +1128,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_GLIBC COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); @@ -1139,6 +1150,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)); @@ -1153,6 +1165,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_HAS_SIGINFO COMPILER_CHECK(alignof(siginfo_t) == alignof(__sanitizer_siginfo)); @@ -1215,7 +1228,7 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); #endif -#if !SANITIZER_HAIKU +#if !SANITIZER_HAIKU && !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(ether_addr); #endif @@ -1255,7 +1268,7 @@ CHECK_TYPE_SIZE(clock_t); CHECK_TYPE_SIZE(clockid_t); #endif -#if !SANITIZER_ANDROID && !SANITIZER_HAIKU +#if !SANITIZER_ANDROID && !SANITIZER_HAIKU && !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(ifaddrs); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); @@ -1285,7 +1298,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 05ebee49f2ab49..377fdca7545fac 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,8 @@ #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H #define SANITIZER_PLATFORM_LIMITS_POSIX_H -#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU +#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU || \ + SANITIZER_EMSCRIPTEN # include "sanitizer_internal_defs.h" # include "sanitizer_mallinfo.h" @@ -29,11 +30,20 @@ # define SANITIZER_HAS_STAT64 0 # define SANITIZER_HAS_STATFS64 0 # endif -# elif SANITIZER_GLIBC || SANITIZER_ANDROID -# define SANITIZER_HAS_STAT64 1 -# define SANITIZER_HAS_STATFS64 1 # elif SANITIZER_HAIKU # include +# elif SANITIZER_EMSCRIPTEN +# define SANITIZER_HAS_STAT64 0 +# define SANITIZER_HAS_STATFS64 0 +# else +// Must be SANITIZER_LINUX then +# define SANITIZER_HAS_STAT64 1 +# define SANITIZER_HAS_STATFS64 1 +# endif + +# if SANITIZER_EMSCRIPTEN +# include // For sigset_t +# include // For clock_t and clockid_t # endif # if defined(__sparc__) @@ -573,7 +583,9 @@ struct __sanitizer_dirent64 { extern unsigned struct_sock_fprog_sz; # endif -# if SANITIZER_HAIKU +# if SANITIZER_EMSCRIPTEN +typedef clock_t __sanitizer_clock_t; +# elif SANITIZER_HAIKU typedef int __sanitizer_clock_t; # elif defined(__x86_64__) && !defined(_LP64) typedef long long __sanitizer_clock_t; @@ -584,6 +596,9 @@ typedef long __sanitizer_clock_t; # if SANITIZER_LINUX || SANITIZER_HAIKU typedef int __sanitizer_clockid_t; typedef unsigned long long __sanitizer_eventfd_t; +# elif SANITIZER_EMSCRIPTEN +typedef clockid_t __sanitizer_clockid_t; +// eventfd is Unix-specific. # endif # if SANITIZER_LINUX @@ -637,6 +652,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 sigset_t __sanitizer_sigset_t; # endif struct __sanitizer_siginfo_pad { @@ -854,7 +871,7 @@ struct __sanitizer_pollfd { short revents; }; -# if SANITIZER_ANDROID || SANITIZER_APPLE +# if SANITIZER_ANDROID || SANITIZER_APPLE || SANITIZER_EMSCRIPTEN typedef unsigned __sanitizer_nfds_t; # else typedef unsigned long __sanitizer_nfds_t; @@ -1593,6 +1610,7 @@ extern const int si_SEGV_ACCERR; typedef void *__sanitizer_timer_t; # endif -#endif // SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU +#endif // SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU || + // SANITIZER_EMSCRIPTEN #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp index 5b2c4e668ca8f9..0aa70bf4a3a0df 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp @@ -96,14 +96,10 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, uptr res = map_res; if (!IsAligned(res, alignment)) { res = (map_res + alignment - 1) & ~(alignment - 1); +#ifndef SANITIZER_EMSCRIPTEN + // Emscripten's fake mmap doesn't support partial unmapping UnmapOrDie((void*)map_res, res - map_res); - } - uptr map_end = map_res + map_size; - uptr end = res + size; - end = RoundUpTo(end, GetPageSizeCached()); - if (end != map_end) { - CHECK_LT(end, map_end); - UnmapOrDie((void*)end, map_end - end); +#endif } return (void*)res; } @@ -147,15 +143,27 @@ void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { } bool MprotectNoAccess(uptr addr, uptr size) { +#if SANITIZER_EMSCRIPTEN + return true; +#else return 0 == internal_mprotect((void*)addr, size, PROT_NONE); +#endif } bool MprotectReadOnly(uptr addr, uptr size) { +#if SANITIZER_EMSCRIPTEN + return true; +#else return 0 == internal_mprotect((void *)addr, size, PROT_READ); +#endif } bool MprotectReadWrite(uptr addr, uptr size) { +#if SANITIZER_EMSCRIPTEN + return true; +#else return 0 == internal_mprotect((void *)addr, size, PROT_READ | PROT_WRITE); +#endif } #if !SANITIZER_APPLE @@ -225,7 +233,17 @@ void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { return (void *)p; } -# if !SANITIZER_APPLE +#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 +#if !SANITIZER_APPLE // 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 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { @@ -256,7 +274,8 @@ void DumpProcessMap() { Report("End of process memory map.\n"); UnmapOrDie(filename, kBufSize); } -# endif +#endif +#endif const char *GetPwd() { return GetEnv("PWD"); @@ -277,6 +296,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); InternalMmapVector buff(kMaxPathLength); MemoryMappedSegment segment(buff.data(), buff.size()); @@ -288,6 +311,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 8e5e87938c3723..fd1b69edea1366 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -85,6 +85,7 @@ bool DontDumpShadowMemory(uptr addr, uptr length) { #endif // MADV_DONTDUMP } +#if !SANITIZER_EMSCRIPTEN static rlim_t getlim(int res) { rlimit rlim; CHECK_EQ(0, getrlimit(res, &rlim)); @@ -149,6 +150,7 @@ void SetAddressSpaceUnlimited() { setlim(RLIMIT_AS, RLIM_INFINITY); CHECK(AddressSpaceIsUnlimited()); } +#endif void Abort() { #if !SANITIZER_GO @@ -248,7 +250,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); @@ -317,6 +321,11 @@ static void SetNonBlock(int fd) { } 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 while (size) { // `read` from `fds[0]` into a dummy buffer to free up the pipe buffer for // more `write` is slower than just recreating a pipe. @@ -343,6 +352,7 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) { } return true; +#endif // SANITIZER_EMSCRIPTEN } bool TryMemCpy(void *dest, const void *src, uptr n) { @@ -394,7 +404,9 @@ void PlatformPrepareForSandboxing(void *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, @@ -519,6 +531,7 @@ void AdjustStackSize(void *attr_) { } #endif // !SANITIZER_GO +#if !SANITIZER_EMSCRIPTEN pid_t StartSubprocess(const char *program, const char *const argv[], const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { @@ -597,6 +610,7 @@ int WaitForProcess(pid_t pid) { } return process_status; } +#endif bool IsStateDetached(int state) { return state == PTHREAD_CREATE_DETACHED; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h b/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h index 7d889111765775..9d6e471bd4f879 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h @@ -15,7 +15,9 @@ # define SANITIZER_REDEFINE_BUILTINS_H // The asm hack only works with GCC and Clang. -# if !defined(_WIN32) && !defined(_AIX) && !defined(__APPLE__) +// XXX Emscripten This does not work in Wasm. +# if !defined(_WIN32) && !defined(_AIX) && !defined(__APPLE__) && \ + !defined(__wasm__) asm(R"( .set memcpy, __sanitizer_internal_memcpy @@ -52,7 +54,7 @@ using vector = Define_SANITIZER_COMMON_NO_REDEFINE_BUILTINS_in_cpp_file; } // namespace std # endif // __cpluplus -# endif // !_WIN32 +# endif // !_WIN32 && !__wasm__ # endif // SANITIZER_REDEFINE_BUILTINS_H #endif // SANITIZER_COMMON_NO_REDEFINE_BUILTINS diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp index d24fae98213aa4..548a298930eff1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp @@ -53,9 +53,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; @@ -66,8 +68,8 @@ void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { top_frame_bp = 0; } -// Sparc implementation 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 47aed488c71a71..75ff41ed52c245 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -33,7 +33,7 @@ static const u32 kStackTraceMax = 255; // 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_APPLE +#if SANITIZER_APPLE || SANITIZER_EMSCRIPTEN # define SANITIZER_CAN_SLOW_UNWIND 0 #else # define SANITIZER_CAN_SLOW_UNWIND 1 @@ -75,6 +75,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 1a0e00d5d5af21..443c589b868260 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -104,9 +104,15 @@ void StackTrace::PrintTo(InternalScopedString *output) const { } 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 CHECK(printer.ProcessAddressFrames(pc)); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h index 6442a2980bf2f9..f6c1cff0548f84 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -74,6 +74,7 @@ class SymbolizerTool { ~SymbolizerTool() {} }; +#if !SANITIZER_EMSCRIPTEN // SymbolizerProcess encapsulates communication between the tool and // external symbolizer program, running in a different subprocess. // SymbolizerProcess may not be used from two threads simultaneously. @@ -149,6 +150,7 @@ class LLVMSymbolizer final : public SymbolizerTool { static const uptr kBufferSize = 16 * 1024; char buffer_[kBufferSize]; }; +#endif // Parses one or more two-line strings in the following format: // diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp index cc31d3d8056f9e..85073e4b1ecb04 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -238,6 +238,7 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { return module; } +#if !SANITIZER_EMSCRIPTEN // For now we assume the following protocol: // For each request of the form // @@ -586,6 +587,7 @@ bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { } return true; } +#endif #endif // !SANITIZER_SYMBOLIZER_MARKUP 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 ab6aee7c9fba77..2510d1b8b0cd17 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -13,7 +13,7 @@ #include "sanitizer_platform.h" #include "sanitizer_symbolizer_markup.h" -#if SANITIZER_POSIX +#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN # include // for dlsym() # include # include @@ -209,6 +209,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { return true; } +#if !SANITIZER_EMSCRIPTEN class Addr2LineProcess final : public SymbolizerProcess { public: Addr2LineProcess(const char *path, const char *module_name) @@ -322,6 +323,7 @@ class Addr2LinePool final : public SymbolizerTool { InternalMmapVector addr2line_pool_; static const uptr dummy_address_ = FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX); }; +#endif # if SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp index 351e00db6fb2dc..fa7f78ee8b7b21 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -25,6 +25,10 @@ # include #endif +#if SANITIZER_EMSCRIPTEN +#include "emscripten_internal.h" +#endif + namespace __sanitizer { #if !SANITIZER_GO @@ -67,7 +71,13 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info, } #endif -#if !SANITIZER_FUCHSIA +#if SANITIZER_EMSCRIPTEN + +static inline bool ReportSupportsColors() { + return _emscripten_sanitizer_use_colors(); +} + +#elif !SANITIZER_FUCHSIA bool ReportFile::SupportsColors() { SpinMutexLock l(mu); @@ -84,7 +94,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 e7f95d33ad0d30..2780f885d5ab8a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -// NetBSD uses libc calls directly -#if !SANITIZER_NETBSD +// NetBSD and Emscripten uses libc calls directly +#if !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN #if SANITIZER_FREEBSD || SANITIZER_APPLE || SANITIZER_SOLARIS # define SYSCALL(name) SYS_ ## name diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h index 8adc420c8cce40..1003205de01300 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h @@ -168,6 +168,8 @@ class SANITIZER_MUTEX ThreadRegistry { typedef GenericScopedLock ThreadRegistryLock; +ThreadRegistry *GetThreadRegistryLocked(); + } // namespace __sanitizer #endif // SANITIZER_THREAD_REGISTRY_H diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index b1d09a9024e7ed..7b79ed1151b1c9 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 2146ed3c27287e..36af4fddf3d34a 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cpp +++ b/compiler-rt/lib/ubsan/ubsan_diag.cpp @@ -414,7 +414,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 25cefd46ce27ce..cd4a1458e7324c 100644 --- a/compiler-rt/lib/ubsan/ubsan_flags.cpp +++ b/compiler-rt/lib/ubsan/ubsan_flags.cpp @@ -19,8 +19,14 @@ #include +#if SANITIZER_EMSCRIPTEN +#include +#include "emscripten_internal.h" +#endif + namespace __ubsan { +#if !SANITIZER_EMSCRIPTEN static const char *GetFlag(const char *flag) { // We cannot call getenv() from inside a preinit array initializer if (SANITIZER_CAN_USE_PREINIT_ARRAY) { @@ -29,6 +35,7 @@ static const char *GetFlag(const char *flag) { return getenv(flag); } } +#endif Flags ubsan_flags; @@ -50,7 +57,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 +76,14 @@ void InitializeFlags() { // Override from user-specified string. parser.ParseString(__ubsan_default_options()); // Override from environment variable. +#if SANITIZER_EMSCRIPTEN + char* options = _emscripten_sanitizer_get_option("UBSAN_OPTIONS"); + parser.ParseString(options); + 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 63319f46734a48..d27f595a54347a 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -798,33 +798,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 c7eb1a967e53fa..357d9524d06de1 100644 --- a/compiler-rt/lib/ubsan/ubsan_platform.h +++ b/compiler-rt/lib/ubsan/ubsan_platform.h @@ -16,7 +16,7 @@ #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ defined(__NetBSD__) || defined(__DragonFly__) || \ (defined(__sun__) && defined(__svr4__)) || defined(_WIN32) || \ - defined(__Fuchsia__) || defined(__HAIKU__) + defined(__Fuchsia__) || defined(__HAIKU__) || 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 68edd3a1b2062e..c64cdebba9bdc8 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() {} @@ -50,9 +50,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/libc/src/string/memory_utils/inline_memcpy.h b/libc/src/string/memory_utils/inline_memcpy.h index 13975e6b3bd0e2..931d2821be3a97 100644 --- a/libc/src/string/memory_utils/inline_memcpy.h +++ b/libc/src/string/memory_utils/inline_memcpy.h @@ -31,7 +31,7 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memcpy.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_builtin #else diff --git a/libc/src/string/memory_utils/inline_memmove.h b/libc/src/string/memory_utils/inline_memmove.h index 71a28c32e4c566..31627669b06bf8 100644 --- a/libc/src/string/memory_utils/inline_memmove.h +++ b/libc/src/string/memory_utils/inline_memmove.h @@ -29,7 +29,7 @@ #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_SMALL_SIZE \ inline_memmove_no_small_size #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_FOLLOW_UP inline_memmove_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_SMALL_SIZE \ inline_memmove_no_small_size diff --git a/libc/src/string/memory_utils/inline_memset.h b/libc/src/string/memory_utils/inline_memset.h index e41bdb626d60eb..da85f09d0db573 100644 --- a/libc/src/string/memory_utils/inline_memset.h +++ b/libc/src/string/memory_utils/inline_memset.h @@ -27,7 +27,7 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memset.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_builtin #else diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h index 5ce040fbcb5991..f3abc391bff820 100644 --- a/libcxx/include/__configuration/abi.h +++ b/libcxx/include/__configuration/abi.h @@ -75,7 +75,8 @@ # define _LIBCPP_ABI_NO_ITERATOR_BASES # define _LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT # define _LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER -# define _LIBCPP_ABI_OPTIMIZED_FUNCTION +// XXX EMSCRIPTEN https://github.com/emscripten-core/emscripten/issues/11022 +//# define _LIBCPP_ABI_OPTIMIZED_FUNCTION # define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO # define _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION # define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h index 0474c1db359dea..5dc26212782561 100644 --- a/libcxx/include/__locale_dir/locale_base_api.h +++ b/libcxx/include/__locale_dir/locale_base_api.h @@ -128,7 +128,9 @@ // (by providing global non-reserved names) and the new API. As we move individual platforms // towards the new way of defining the locale base API, this should disappear since each platform // will define those directly. -# if defined(__MVS__) +# if defined(__EMSCRIPTEN__) +# include +# elif defined(__MVS__) # include <__locale_dir/locale_base_api/ibm.h> # elif defined(__OpenBSD__) # include <__locale_dir/locale_base_api/openbsd.h> diff --git a/libcxx/include/__verbose_abort b/libcxx/include/__verbose_abort index f8b696733e2b38..2440bcc8e5c15b 100644 --- a/libcxx/include/__verbose_abort +++ b/libcxx/include/__verbose_abort @@ -37,7 +37,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD // make sure that the program terminates but without taking any complex dependencies in this header. #if !defined(_LIBCPP_VERBOSE_ABORT) -# if !_LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT +// XXX EMSCRIPTEN avoid __libcpp_verbose_abort in release builds due to code +// size +# if !_LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT || (defined(__EMSCRIPTEN__) && defined(NDEBUG)) // The decltype is there to suppress -Wunused warnings in this configuration. void __use(const char*, ...); # define _LIBCPP_VERBOSE_ABORT(...) (decltype(::std::__use(__VA_ARGS__))(), __builtin_abort()) diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo index f67d61e3680879..7684f54a6f85fc 100644 --- a/libcxx/include/typeinfo +++ b/libcxx/include/typeinfo @@ -318,7 +318,10 @@ public: [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t hash_code() const _NOEXCEPT { return __impl::__hash(__type_name); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool operator==(const type_info& __arg) const _NOEXCEPT { + // XXX Emscripten: adding `always_inline` fixes + // https://github.com/emscripten-core/emscripten/issues/13330 + __attribute__((always_inline)) _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool + operator==(const type_info& __arg) const _NOEXCEPT { // When evaluated in a constant expression, both type infos simply can't come // from different translation units, so it is sufficient to compare their addresses. if (__libcpp_is_constant_evaluated()) { diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp index 745db87ce3736e..4c6853fc40e380 100644 --- a/libcxx/src/filesystem/operations.cpp +++ b/libcxx/src/filesystem/operations.cpp @@ -41,7 +41,7 @@ #include // since Linux 4.5 and FreeBSD 13, but the Linux libc wrapper is only provided by glibc >= 2.27 and musl -#if _LIBCPP_GLIBC_PREREQ(2, 27) || _LIBCPP_HAS_MUSL_LIBC || defined(__FreeBSD__) +#if (_LIBCPP_GLIBC_PREREQ(2, 27) || _LIBCPP_HAS_MUSL_LIBC || defined(__FreeBSD__)) && !defined(__EMSCRIPTEN__) # define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE #endif diff --git a/libcxx/src/support/runtime/exception_fallback.ipp b/libcxx/src/support/runtime/exception_fallback.ipp index dca904e902da13..a5bc1a39936905 100644 --- a/libcxx/src/support/runtime/exception_fallback.ipp +++ b/libcxx/src/support/runtime/exception_fallback.ipp @@ -35,6 +35,7 @@ terminate_handler set_terminate(terminate_handler func) noexcept { terminate_handler get_terminate() noexcept { return __libcpp_atomic_load(&__terminate_handler); } +#ifndef __EMSCRIPTEN__ // We provide this in JS [[noreturn]] void terminate() noexcept { #if _LIBCPP_HAS_EXCEPTIONS try { @@ -49,13 +50,16 @@ terminate_handler get_terminate() noexcept { return __libcpp_atomic_load(&__term } #endif // _LIBCPP_HAS_EXCEPTIONS } +#endif // !__EMSCRIPTEN__ +#if !defined(__EMSCRIPTEN__) bool uncaught_exception() noexcept { return uncaught_exceptions() > 0; } int uncaught_exceptions() noexcept { #warning uncaught_exception not yet implemented __libcpp_verbose_abort("uncaught_exceptions not yet implemented\n"); } +#endif // !__EMSCRIPTEN__ exception::~exception() noexcept {} diff --git a/libcxx/src/verbose_abort.cpp b/libcxx/src/verbose_abort.cpp index 94bdb451dee7a6..01ff59893db254 100644 --- a/libcxx/src/verbose_abort.cpp +++ b/libcxx/src/verbose_abort.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef __BIONIC__ # include @@ -30,6 +31,12 @@ _LIBCPP_WEAK void __libcpp_verbose_abort(char const* format, ...) noexcept { va_list list; va_start(list, format); std::vfprintf(stderr, format, list); + // TODO(sbc): Add newline here unconditionally. libc++ seems inconsistent about strings + // passed to __libcpp_verbose_abort. The _LIBCPP_VERBOSE_ABORT macro seems to never use + // newlines, but _LIBCPP_ASSERTION_HANDLER does include a newline. + if (format[strlen(format) - 1] != '\n') { + std::fputc('\n', stderr); + } va_end(list); } diff --git a/libcxxabi/src/abort_message.cpp b/libcxxabi/src/abort_message.cpp index d51d9d87d35e02..4d1981ee134c28 100644 --- a/libcxxabi/src/abort_message.cpp +++ b/libcxxabi/src/abort_message.cpp @@ -28,12 +28,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.) + abort(); +#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 5d7edae697d674..443ac285ce0c7e 100644 --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -273,6 +273,13 @@ handler, _Unwind_RaiseException may return. In that case, __cxa_throw will call terminate, assuming that there was no handler for the exception. */ + +#if defined(__EMSCRIPTEN__) && defined(__WASM_EXCEPTIONS__) && !defined(NDEBUG) +extern "C" { +void __throw_exception_with_stack_trace(_Unwind_Exception*); +} // extern "C" +#endif + void #ifdef __wasm__ // In Wasm, a destructor returns its argument @@ -293,6 +300,10 @@ __cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FU #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); +#elif defined(__EMSCRIPTEN__) && defined(__WASM_EXCEPTIONS__) && !defined(NDEBUG) + // In debug mode, call a JS library function to use WebAssembly.Exception JS + // API, which enables us to include stack traces + __throw_exception_with_stack_trace(&exception_header->unwindHeader); #else _Unwind_RaiseException(&exception_header->unwindHeader); #endif @@ -647,6 +658,10 @@ void __cxa_rethrow() { } #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); +#elif defined(__EMSCRIPTEN__) && defined(__WASM_EXCEPTIONS__) && !defined(NDEBUG) + // In debug mode, call a JS library function to use WebAssembly.Exception JS + // API, which enables us to include stack traces + __throw_exception_with_stack_trace(&exception_header->unwindHeader); #else _Unwind_RaiseException(&exception_header->unwindHeader); #endif @@ -772,6 +787,11 @@ __cxa_rethrow_primary_exception(void* thrown_object) dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup; #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); +#elif defined(__EMSCRIPTEN__) && defined(__WASM_EXCEPTIONS__) && !defined(NDEBUG) + // In debug mode, call a JS library function to use + // WebAssembly.Exception JS API, which enables us to include stack + // traces + __throw_exception_with_stack_trace(&dep_exception_header->unwindHeader); #else _Unwind_RaiseException(&dep_exception_header->unwindHeader); #endif diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h index fa4c4dc55bde24..e7dc8d899a11dd 100644 --- a/libcxxabi/src/cxa_exception.h +++ b/libcxxabi/src/cxa_exception.h @@ -19,6 +19,26 @@ namespace __cxxabiv1 { +#ifdef __EMSCRIPTEN_EXCEPTIONS__ + +struct _LIBCXXABI_HIDDEN __cxa_exception { + size_t referenceCount; + std::type_info *exceptionType; + // In wasm, destructors return 'this' as in ARM + void* (*exceptionDestructor)(void *); + uint8_t caught; + uint8_t rethrown; + void *adjustedPtr; + // Add padding to ensure that the size of __cxa_exception is a multiple of + // the maximum useful alignment for the target machine. This ensures that + // the thrown object that follows has that correct alignment. + void *padding; +}; + +static_assert(sizeof(__cxa_exception) % alignof(max_align_t) == 0, "__cxa_exception must have a size that is multiple of max alignment"); + +#else + static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0 static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1 static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++ @@ -166,6 +186,8 @@ extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast (); extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception (); extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception); +#endif // !__EMSCRIPTEN_EXCEPTIONS__ + } // namespace __cxxabiv1 #endif // _CXA_EXCEPTION_H diff --git a/libcxxabi/src/cxa_guard_impl.h b/libcxxabi/src/cxa_guard_impl.h index 191a589176b1a3..72efcd1e83c902 100644 --- a/libcxxabi/src/cxa_guard_impl.h +++ b/libcxxabi/src/cxa_guard_impl.h @@ -64,6 +64,11 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#include +#endif + #ifndef _LIBCXXABI_HAS_NO_THREADS # if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) # pragma comment(lib, "pthread") @@ -425,6 +430,13 @@ void PlatformFutexWake(int* addr) { __tsan_release(addr); futex(reinterpret_cast(addr), WAKE, INT_MAX, NULL, NULL); } +#elif defined(__EMSCRIPTEN__) +void PlatformFutexWait(int* addr, int expect) { + emscripten_futex_wait(addr, expect, INFINITY); +} +void PlatformFutexWake(int* addr) { + emscripten_futex_wake(addr, INT_MAX); +} #elif defined(SYS_futex) void PlatformFutexWait(int* addr, int expect) { constexpr int WAIT = 0; diff --git a/libcxxabi/src/cxa_handlers.cpp b/libcxxabi/src/cxa_handlers.cpp index f879ff0d8ff186..b95d108093ad36 100644 --- a/libcxxabi/src/cxa_handlers.cpp +++ b/libcxxabi/src/cxa_handlers.cpp @@ -73,7 +73,7 @@ __attribute__((noreturn)) void terminate() noexcept { -#ifndef _LIBCXXABI_NO_EXCEPTIONS +#if !defined(_LIBCXXABI_NO_EXCEPTIONS) && !defined(__EMSCRIPTEN_EXCEPTIONS__) // If there might be an uncaught exception using namespace __cxxabiv1; __cxa_eh_globals* globals = __cxa_get_globals_fast(); diff --git a/libcxxabi/src/cxa_noexception.cpp b/libcxxabi/src/cxa_noexception.cpp index 29381458f15d3d..182253446393a4 100644 --- a/libcxxabi/src/cxa_noexception.cpp +++ b/libcxxabi/src/cxa_noexception.cpp @@ -49,6 +49,47 @@ __cxa_uncaught_exception() throw() { return false; } unsigned int __cxa_uncaught_exceptions() throw() { return 0; } +#if __EMSCRIPTEN__ +// Under emscripten this code is also linked when building when +// DISABLE_EXCEPTION_CATCHING is set but DISABLE_EXCEPTION_THROWING is not. +// TODO(sbc): Perhaps just call std::terminate here. It could +// just be some test code that needs updating. +void *__cxa_allocate_exception(size_t thrown_size) throw() { + char* allocation = (char*)malloc(thrown_size + sizeof(__cxa_exception)); + return allocation + sizeof(__cxa_exception); +} + +static +inline +__cxa_exception* +cxa_exception_from_thrown_object(void* thrown_object) +{ + return static_cast<__cxa_exception*>(thrown_object) - 1; +} + +// Free a __cxa_exception object allocated with __cxa_allocate_exception. +void __cxa_free_exception(void *thrown_object) throw() { + // Compute the size of the padding before the header. + char *raw_buffer = + ((char *)cxa_exception_from_thrown_object(thrown_object)); + free((void *)raw_buffer); +} + +// This function is called from make_exception_ptr in libcxx unless +// -fno-exceptions is not given. We have definitions of this function in +// cxa_exception.cpp and cxa_exception_emscripten.cpp, but unlike other +// platforms, we use those files only when one of Emscripten EH or Wasm EH is +// used, and we use this cxa_noexceptions.cpp in case of -fignore-exceptions, +// which is our default. So we add a definition here to prevent a link failure. +__cxa_exception* +__cxa_init_primary_exception(void* object, + std::type_info* tinfo, + void*(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(object); + return exception_header; +} +#endif + } // extern "C" // provide dummy implementations for the 'no exceptions' case. diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp index 77b2eb53af0e43..360c9f4be9d226 100644 --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -729,6 +729,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, const uint8_t* lpStart = lpStartEncoding == DW_EH_PE_omit ? (const uint8_t*)funcStart : (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base); + (void)(lpStart); // Unused when using SjLj/Wasm exceptions uint8_t ttypeEncoding = *lsda++; if (ttypeEncoding != DW_EH_PE_omit) { @@ -742,7 +743,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // includes current PC. uint8_t callSiteEncoding = *lsda++; #if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__WASM_EXCEPTIONS__) - (void)callSiteEncoding; // When using SjLj/Wasm exceptions, callSiteEncoding is never used + (void)callSiteEncoding; // Unused when using SjLj/Wasm exceptions #endif uint32_t callSiteTableLength = static_cast(readULEB128(&lsda)); const uint8_t* callSiteTableStart = lsda; diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp index 402a52c741012d..a883aa328e7a43 100644 --- a/libcxxabi/src/cxa_thread_atexit.cpp +++ b/libcxxabi/src/cxa_thread_atexit.cpp @@ -106,16 +106,21 @@ namespace { #endif // HAVE___CXA_THREAD_ATEXIT_IMPL -#if defined(__linux__) || defined(__Fuchsia__) +#if defined(__linux__) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__) extern "C" { _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() { #ifdef HAVE___CXA_THREAD_ATEXIT_IMPL return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); #else +#ifndef __EMSCRIPTEN__ + // Emscripten doesn't implement __cxa_thread_atexit_impl, so we can simply + // avoid this check. if (__cxa_thread_atexit_impl) { return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); - } else { + } else +#endif + { // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for // one-time initialization and __cxa_atexit() for destruction) static DtorsManager manager; @@ -142,5 +147,5 @@ extern "C" { #endif // HAVE___CXA_THREAD_ATEXIT_IMPL } } // extern "C" -#endif // defined(__linux__) || defined(__Fuchsia__) +#endif // defined(__linux__) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__) } // namespace __cxxabiv1 diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index d185f2618a7eab..1b38eff2c24686 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -1549,5 +1549,64 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info, not_public_path, use_strcmp); } +} // __cxxabiv1 + + +// XXX EMSCRIPTEN +#if defined(__wasm__) && !defined(__WASM_EXCEPTIONS__) + +#include "cxa_exception.h" + +namespace __cxxabiv1 +{ + +// 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(catchType); + //std::type_info *t2 = static_cast(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; +} + +static +inline +__cxa_exception* +cxa_exception_from_thrown_object(void* thrown_object) +{ + return static_cast<__cxa_exception*>(thrown_object) - 1; +} + +void *__cxa_get_exception_ptr(void *thrown_object) throw() { + // Get pointer which is expected to be received by catch clause in C++ code. + // It may be adjusted when the pointer is casted to some of the exception + // object base classes (e.g. when virtual inheritance is used). When a pointer + // is thrown this method should return the thrown pointer itself. + // Work around a fastcomp bug, this code is still included for some reason in + // a build without exceptions support. + __cxa_exception* ex = cxa_exception_from_thrown_object(thrown_object); + bool is_pointer = !!dynamic_cast<__pointer_type_info*>(ex->exceptionType); + if (is_pointer) + return *(void**)thrown_object; + if (ex->adjustedPtr) + return ex->adjustedPtr; + return ex; +} + +} } // __cxxabiv1 + +#endif // __wasm__ && !__WASM_EXCEPTIONS__ +