Author: Sam Clegg Date: 2022-05-22T19:08:19-07:00 New Revision: 57626a57ad4bb35367f0b361bd80ce9999b3266a
URL: https://github.com/llvm/llvm-project/commit/57626a57ad4bb35367f0b361bd80ce9999b3266a DIFF: https://github.com/llvm/llvm-project/commit/57626a57ad4bb35367f0b361bd80ce9999b3266a.diff LOG: Rebase of changed from emscripten-libs-13.0.0 onto llvmorg-14.0.0 Added: Modified: compiler-rt/lib/asan/asan_errors.cpp compiler-rt/lib/asan/asan_flags.cpp compiler-rt/lib/asan/asan_interceptors.cpp compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp compiler-rt/lib/asan/asan_malloc_linux.cpp compiler-rt/lib/asan/asan_mapping.h compiler-rt/lib/asan/asan_poisoning.cpp compiler-rt/lib/asan/asan_poisoning.h compiler-rt/lib/asan/asan_posix.cpp compiler-rt/lib/asan/asan_rtl.cpp compiler-rt/lib/asan/asan_shadow_setup.cpp compiler-rt/lib/asan/asan_thread.cpp compiler-rt/lib/builtins/fp_compare_impl.inc compiler-rt/lib/interception/interception.h compiler-rt/lib/interception/interception_linux.h compiler-rt/lib/lsan/lsan.cpp compiler-rt/lib/lsan/lsan_allocator.cpp compiler-rt/lib/lsan/lsan_allocator.h compiler-rt/lib/lsan/lsan_common.cpp compiler-rt/lib/lsan/lsan_common.h compiler-rt/lib/lsan/lsan_common_linux.cpp compiler-rt/lib/lsan/lsan_interceptors.cpp compiler-rt/lib/lsan/lsan_linux.cpp compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp compiler-rt/lib/sanitizer_common/sanitizer_linux.h compiler-rt/lib/sanitizer_common/sanitizer_platform.h compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc compiler-rt/lib/ubsan/ubsan_checks.inc compiler-rt/lib/ubsan/ubsan_diag.cpp compiler-rt/lib/ubsan/ubsan_flags.cpp compiler-rt/lib/ubsan/ubsan_handlers.cpp compiler-rt/lib/ubsan/ubsan_platform.h compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp libcxx/include/__config libcxx/include/locale libcxx/include/typeinfo libcxx/src/include/config_elast.h libcxx/src/new.cpp libcxx/src/support/runtime/exception_fallback.ipp libcxxabi/include/cxxabi.h libcxxabi/src/abort_message.cpp libcxxabi/src/cxa_exception.cpp libcxxabi/src/cxa_exception.h libcxxabi/src/cxa_handlers.cpp libcxxabi/src/cxa_personality.cpp libcxxabi/src/cxa_thread_atexit.cpp libcxxabi/src/private_typeinfo.cpp libcxxabi/src/stdlib_new_delete.cpp Removed: ################################################################################ diff --git a/compiler-rt/lib/asan/asan_errors.cpp b/compiler-rt/lib/asan/asan_errors.cpp index a22bf130d8233..f1ccbb8f50f82 100644 --- a/compiler-rt/lib/asan/asan_errors.cpp +++ b/compiler-rt/lib/asan/asan_errors.cpp @@ -482,6 +482,17 @@ ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, scariness.Scare(bug_type_score + read_after_free_bonus, bug_descr); if (far_from_bounds) scariness.Scare(10, "far-from-bounds"); } +#if SANITIZER_EMSCRIPTEN + // If address is in the first page (64 KB), then it is likely that the + // access is a result of a null pointer dereference. + else if (addr < 65536) { + bug_descr = "null-pointer-dereference"; + scariness.Scare(25, bug_descr); + } else if (AddrIsInShadow(addr)) { + bug_descr = "shadow-access"; + scariness.Scare(25, bug_descr); + } +#endif } } diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp index 9ea899f84b4b7..d7ef1a109f2ee 100644 --- a/compiler-rt/lib/asan/asan_flags.cpp +++ b/compiler-rt/lib/asan/asan_flags.cpp @@ -22,6 +22,12 @@ #include "ubsan/ubsan_flags.h" #include "ubsan/ubsan_platform.h" +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include <emscripten/em_asm.h> +#endif + + namespace __asan { Flags asan_flags_dont_use_directly; // use via flags(). @@ -54,7 +60,11 @@ void InitializeFlags() { CommonFlags cf; cf.CopyFrom(*common_flags()); cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS; +#if !SANITIZER_EMSCRIPTEN + // getenv on emscripten uses malloc, which we can't when using LSan. + // You can't run external symbolizer executables anyway. cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); +#endif cf.malloc_context_size = kDefaultMallocContextSize; cf.intercept_tls_get_addr = true; cf.exitcode = 1; @@ -115,6 +125,27 @@ void InitializeFlags() { 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 = (char*)(long)EM_ASM_DOUBLE({ \ + return withBuiltinMalloc(function () { \ + return allocateUTF8(Module[name] || 0); \ + }); \ + }); \ + parser.ParseString(options); \ + emscripten_builtin_free(options); + + MAKE_OPTION_LOAD(asan_parser, 'ASAN_OPTIONS'); +#if CAN_SANITIZE_LEAKS + MAKE_OPTION_LOAD(lsan_parser, 'LSAN_OPTIONS'); +#endif +#if CAN_SANITIZE_UB + MAKE_OPTION_LOAD(ubsan_parser, 'UBSAN_OPTIONS'); +#endif +#else // Override from command line. asan_parser.ParseStringFromEnv("ASAN_OPTIONS"); #if CAN_SANITIZE_LEAKS @@ -123,12 +154,18 @@ void InitializeFlags() { #if CAN_SANITIZE_UB ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS"); #endif +#endif // SANITIZER_EMSCRIPTEN InitializeCommonFlags(); // TODO(eugenis): dump all flags at verbosity>=2? if (Verbosity()) ReportUnrecognizedFlags(); +#if SANITIZER_EMSCRIPTEN + if (common_flags()->malloc_context_size <= 1) + StackTrace::snapshot_stack = false; +#endif // SANITIZER_EMSCRIPTEN + if (common_flags()->help) { // TODO(samsonov): print all of the flags (ASan, LSan, common). asan_parser.PrintFlagDescriptions(); diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 2ff314a5a9cbd..e106cbd52cbcd 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -23,10 +23,10 @@ #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" -// There is no general interception at all on Fuchsia. +// 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" @@ -708,4 +708,4 @@ void InitializeAsanInterceptors() { } // namespace __asan -#endif // !SANITIZER_FUCHSIA +#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp index 9c316bb957493..9e275ba211e2f 100644 --- a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp +++ b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp @@ -30,7 +30,7 @@ void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, size); } -#if SANITIZER_FUCHSIA +#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 @@ -40,4 +40,4 @@ extern "C" decltype(__asan_memcpy) memcpy[[gnu::alias("__asan_memcpy")]]; extern "C" decltype(__asan_memmove) memmove[[gnu::alias("__asan_memmove")]]; extern "C" decltype(__asan_memset) memset[[gnu::alias("__asan_memset")]]; -#endif // SANITIZER_FUCHSIA +#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 bab80b96f584b..a7c04435df811 100644 --- a/compiler-rt/lib/asan/asan_malloc_linux.cpp +++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp @@ -15,7 +15,7 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \ - SANITIZER_NETBSD || SANITIZER_SOLARIS + SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # include "asan_allocator.h" # include "asan_interceptors.h" diff --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h index 4ff09b103d5f2..586896b3b8a81 100644 --- a/compiler-rt/lib/asan/asan_mapping.h +++ b/compiler-rt/lib/asan/asan_mapping.h @@ -258,6 +258,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) \ (((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 bbc7db4709e14..cb3868b400620 100644 --- a/compiler-rt/lib/asan/asan_poisoning.cpp +++ b/compiler-rt/lib/asan/asan_poisoning.cpp @@ -176,6 +176,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 600bd011f304c..e34de6c09dd5a 100644 --- a/compiler-rt/lib/asan/asan_poisoning.h +++ b/compiler-rt/lib/asan/asan_poisoning.h @@ -51,6 +51,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 63ad735f8bba6..cfd158c88a9bf 100644 --- a/compiler-rt/lib/asan/asan_posix.cpp +++ b/compiler-rt/lib/asan/asan_posix.cpp @@ -40,6 +40,9 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { } bool PlatformUnpoisonStacks() { +#if SANITIZER_EMSCRIPTEN + return false; +#else stack_t signal_stack; CHECK_EQ(0, sigaltstack(nullptr, &signal_stack)); uptr sigalt_bottom = (uptr)signal_stack.ss_sp; @@ -63,6 +66,7 @@ bool PlatformUnpoisonStacks() { &tls_size); UnpoisonStack(default_bottom, default_bottom + stack_size, "default"); return true; +#endif } // ---------------------- TSD ---------------- {{{1 diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp index f0bbbf32e6a64..3526526dbcfac 100644 --- a/compiler-rt/lib/asan/asan_rtl.cpp +++ b/compiler-rt/lib/asan/asan_rtl.cpp @@ -52,6 +52,7 @@ static void AsanDie() { Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); SleepForSeconds(flags()->sleep_before_dying); } +#if !SANITIZER_EMSCRIPTEN if (flags()->unmap_shadow_on_exit) { if (kMidMemBeg) { UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg); @@ -61,6 +62,7 @@ static void AsanDie() { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } +#endif } static void CheckUnwind() { @@ -305,6 +307,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 @@ -312,6 +315,7 @@ static void InitializeHighMemEnd() { kHighMemEnd |= (GetMmapGranularity() << ASAN_SHADOW_SCALE) - 1; #endif // !ASAN_FIXED_MAPPING CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); +#endif // !SANITIZER_EMSCRIPTEN } void PrintAddressSpaceLayout() { @@ -439,7 +443,9 @@ static void AsanInitInternal() { InitializeShadowMemory(); AsanTSDInit(PlatformTSDDtor); +#if !SANITIZER_EMSCRIPTEN InstallDeadlySignalHandlers(AsanOnDeadlySignal); +#endif AllocatorOptions allocator_options; allocator_options.SetFrom(flags(), common_flags()); diff --git a/compiler-rt/lib/asan/asan_shadow_setup.cpp b/compiler-rt/lib/asan/asan_shadow_setup.cpp index fc6de39622b51..83f1906aaebf7 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 2b06c3c4e7c04..d450017021864 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -105,8 +105,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 @@ -264,7 +266,9 @@ thread_return_t AsanThread::ThreadStart(tid_t os_id) { Init(); asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); +#endif if (!start_routine_) { // start_routine_ == 0 if we're on the main thread or on one of the diff --git a/compiler-rt/lib/builtins/fp_compare_impl.inc b/compiler-rt/lib/builtins/fp_compare_impl.inc index 40fc7df4c679c..645bfc1656d51 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). -#ifdef __aarch64__ +#if defined(__aarch64__) || 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 d8dc092c45f56..aeb188f4fc7e7 100644 --- a/compiler-rt/lib/interception/interception.h +++ b/compiler-rt/lib/interception/interception.h @@ -18,7 +18,7 @@ #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \ !SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \ - !SANITIZER_SOLARIS + !SANITIZER_SOLARIS && !SANITIZER_EMSCRIPTEN # error "Interception doesn't work on this operating system." #endif @@ -130,6 +130,11 @@ const interpose_substitution substitution_##func_name[] \ extern "C" ret_type func(__VA_ARGS__); # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); +#elif SANITIZER_EMSCRIPTEN +# define WRAP(x) x +# define WRAPPER_NAME(x) #x +# define INTERCEPTOR_ATTRIBUTE +# define DECLARE_WRAPPER(ret_type, func, ...) #elif SANITIZER_FREEBSD || SANITIZER_NETBSD # define WRAP(x) __interceptor_ ## x # define WRAPPER_NAME(x) "__interceptor_" #x @@ -157,6 +162,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_MAC # define PTR_TO_REAL(x) real_##x # define REAL(x) __interception::PTR_TO_REAL(x) @@ -193,7 +205,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_MAC && !SANITIZER_FUCHSIA +#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN # define DEFINE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ @@ -263,16 +275,16 @@ const interpose_substitution substitution_##func_name[] \ // INTERCEPT_FUNCTION macro, only its name. namespace __interception { #if defined(_WIN64) -typedef unsigned long long uptr; +typedef unsigned long long uptr; // NOLINT #else -typedef unsigned long uptr; +typedef unsigned long uptr; // NOLINT #endif // _WIN64 } // namespace __interception #define INCLUDED_FROM_INTERCEPTION_LIB #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # include "interception_linux.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) diff --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h index a08f8cb98c409..6d3957e570267 100644 --- a/compiler-rt/lib/interception/interception_linux.h +++ b/compiler-rt/lib/interception/interception_linux.h @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) # error "interception_linux.h should be included from interception library only" diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp index b6adc248157b6..622f9335fb2d2 100644 --- a/compiler-rt/lib/lsan/lsan.cpp +++ b/compiler-rt/lib/lsan/lsan.cpp @@ -19,6 +19,11 @@ #include "lsan_common.h" #include "lsan_thread.h" +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include <emscripten/em_asm.h> +#endif + bool lsan_inited; bool lsan_init_is_running; @@ -53,7 +58,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; @@ -71,7 +80,22 @@ static void InitializeFlags() { // Override from user-specified string. const char *lsan_default_options = __lsan_default_options(); parser.ParseString(lsan_default_options); - parser.ParseStringFromEnv("LSAN_OPTIONS"); +#if SANITIZER_EMSCRIPTEN + char *options = (char*) EM_ASM_INT({ + return withBuiltinMalloc(function () { + return allocateUTF8(Module['LSAN_OPTIONS'] || 0); + }); + }); + parser.ParseString(options); + emscripten_builtin_free(options); +#else + parser.ParseString(GetEnv("LSAN_OPTIONS")); +#endif // SANITIZER_EMSCRIPTEN + +#if SANITIZER_EMSCRIPTEN + if (common_flags()->malloc_context_size <= 1) + StackTrace::snapshot_stack = false; +#endif // SANITIZER_EMSCRIPTEN InitializeCommonFlags(); @@ -97,7 +121,10 @@ extern "C" void __lsan_init() { InitTlsSize(); InitializeInterceptors(); InitializeThreadRegistry(); +#if !SANITIZER_EMSCRIPTEN + // Emscripten does not have signals InstallDeadlySignalHandlers(LsanOnDeadlySignal); +#endif InitializeMainThread(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp index ea4c6c9cf6470..1e9de740e065b 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 = 8ULL << 30; diff --git a/compiler-rt/lib/lsan/lsan_allocator.h b/compiler-rt/lib/lsan/lsan_allocator.h index 45c6ac406f8a1..da741503ebe20 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.h +++ b/compiler-rt/lib/lsan/lsan_allocator.h @@ -50,7 +50,7 @@ struct ChunkMetadata { }; #if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \ - defined(__arm__) || SANITIZER_RISCV64 || defined(__hexagon__) + defined(__arm__) || SANITIZER_RISCV64 || defined(__hexagon__) || defined(__wasm__) template <typename AddressSpaceViewTy> struct AP32 { static const uptr kSpaceBeg = 0; diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp index fd7aa38d99db6..b52106537a677 100644 --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -25,6 +25,10 @@ #include "sanitizer_common/sanitizer_thread_registry.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" +#if SANITIZER_EMSCRIPTEN +#include "lsan/lsan_allocator.h" +#endif + #if CAN_SANITIZE_LEAKS namespace __lsan { @@ -115,7 +119,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)); } @@ -273,7 +277,16 @@ void ScanRangeForPointers(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 = *reinterpret_cast<void **>(pp); if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue; @@ -297,6 +310,14 @@ void ScanRangeForPointers(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", + pp, cache_begin, cache_end); + continue; + } +#endif + m.set_tag(tag); LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", (void *)pp, p, (void *)chunk, @@ -362,6 +383,7 @@ static void ProcessThreadRegistry(Frontier *frontier) { } } +#if !SANITIZER_EMSCRIPTEN // Scans thread data (stacks and TLS) for heap pointers. static void ProcessThreads(SuspendedThreadsList const &suspended_threads, Frontier *frontier) { @@ -480,6 +502,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, // Add pointers reachable from ThreadContexts ProcessThreadRegistry(frontier); } +#endif // !SANITIZER_EMSCRIPTEN # endif // SANITIZER_FUCHSIA @@ -499,14 +522,22 @@ void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, kReachable); } +#if SANITIZER_EMSCRIPTEN +extern "C" uptr emscripten_get_heap_size(); +#endif + static void ProcessRootRegion(Frontier *frontier, const RootRegion &root_region) { +#if SANITIZER_EMSCRIPTEN + ScanRootRegion(frontier, root_region, 0, emscripten_get_heap_size(), true); +#else MemoryMappingLayout proc_maps(/*cache_enabled*/ true); MemoryMappedSegment segment; while (proc_maps.Next(&segment)) { ScanRootRegion(frontier, root_region, segment.start, segment.end, segment.IsReadable()); } +#endif // SANITIZER_EMSCRIPTEN } // Scans root regions for heap pointers. @@ -675,7 +706,9 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads, CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg); CHECK(param); CHECK(!param->success); +#if !SANITIZER_EMSCRIPTEN ReportUnsuspendedThreads(suspended_threads); +#endif ClassifyAllChunks(suspended_threads, ¶m->frontier); ForEachChunk(CollectLeaksCb, ¶m->leaks); // Clean up for subsequent leak checks. This assumes we did not overwrite any @@ -771,6 +804,53 @@ static int DoRecoverableLeakCheck() { void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); } +<<<<<<< HEAD +======= +Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) { + Suppression *s = nullptr; + + // Suppress by module name. + if (const char *module_name = + Symbolizer::GetOrInit()->GetModuleNameForPc(addr)) + if (context.Match(module_name, kSuppressionLeak, &s)) + return s; + + // Suppress by file or function name. + SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr); + for (SymbolizedStack *cur = frames; cur; cur = cur->next) { + if (context.Match(cur->info.function, kSuppressionLeak, &s) || + context.Match(cur->info.file, kSuppressionLeak, &s)) { + break; + } + } + frames->ClearAll(); + return s; +} + +Suppression *LeakSuppressionContext::GetSuppressionForStack( + u32 stack_trace_id) { + LazyInit(); + StackTrace stack = StackDepotGet(stack_trace_id); + for (uptr i = 0; i < stack.size; i++) { +#if SANITIZER_EMSCRIPTEN + // On Emscripten, the stack trace is the actual call site, not + // the code that would be executed after the return. + // Therefore, StackTrace::GetPreviousInstructionPc is not needed. + Suppression *s = GetSuppressionForAddr(stack.trace[i]); +#else + Suppression *s = GetSuppressionForAddr( + StackTrace::GetPreviousInstructionPc(stack.trace[i])); +#endif + if (s) { + suppressed_stacks_sorted = false; + suppressed_stacks.push_back(stack_trace_id); + return s; + } + } + return nullptr; +} + +>>>>>>> 2bbe2c4b7413 (Rebase of changed from emscripten-libs-12.0.0 onto llvmorg-13.0.0) ///// LeakReport implementation. ///// // A hard limit on the number of distinct leaks, to avoid quadratic complexity diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h index 6b06c4517cd5d..11c673b97473b 100644 --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -44,7 +44,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 @@ -255,6 +255,10 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches); void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg); +// Scans thread data (stacks and TLS) for heap pointers. +void ProcessThreads(SuspendedThreadsList const &suspended_threads, + Frontier *frontier); + // If called from the main thread, updates the main thread's TID in the thread // registry. We need this to handle processes that fork() without a subsequent // exec(), which invalidates the recorded TID. To update it, we must call diff --git a/compiler-rt/lib/lsan/lsan_common_linux.cpp b/compiler-rt/lib/lsan/lsan_common_linux.cpp index 692ad35169e1d..20cc3a55d4be0 100644 --- a/compiler-rt/lib/lsan/lsan_common_linux.cpp +++ b/compiler-rt/lib/lsan/lsan_common_linux.cpp @@ -15,7 +15,7 @@ #include "sanitizer_common/sanitizer_platform.h" #include "lsan_common.h" -#if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD) +#if CAN_SANITIZE_LEAKS && SANITIZER_LINUX #include <link.h> #include "sanitizer_common/sanitizer_common.h" diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index 205e85685a7fa..c7032032ff9a7 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -403,6 +403,18 @@ INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK #endif +#if SANITIZER_EMSCRIPTEN +#define __ATTRP_C11_THREAD ((void*)(uptr)-1) +extern "C" { + int emscripten_builtin_pthread_create(void *thread, void *attr, + void *(*callback)(void *), void *arg); + int emscripten_builtin_pthread_join(void *th, void **ret); + int emscripten_builtin_pthread_detach(void *th); + void *emscripten_builtin_malloc(size_t size); + void emscripten_builtin_free(void *); +} +#endif + #if SANITIZER_INTERCEPT_STRERROR INTERCEPTOR(char *, strerror, int errnum) { __lsan::ScopedInterceptorDisabler disabler; @@ -438,7 +450,11 @@ extern "C" void *__lsan_thread_start_func(void *arg) { while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) internal_sched_yield(); ThreadStart(tid, GetTid()); +#if SANITIZER_EMSCRIPTEN + emscripten_builtin_free(p); +#else atomic_store(&p->tid, 0, memory_order_release); +#endif return callback(param); } @@ -447,17 +463,24 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, ENSURE_LSAN_INITED; EnsureMainThreadIDIsCorrect(); __sanitizer_pthread_attr_t myattr; - if (!attr) { + if (!attr || attr == __ATTRP_C11_THREAD) { pthread_attr_init(&myattr); attr = &myattr; } AdjustStackSize(attr); int detached = 0; pthread_attr_getdetachstate(attr, &detached); +#if SANITIZER_EMSCRIPTEN + ThreadParam *p = (ThreadParam *) emscripten_builtin_malloc(sizeof(ThreadParam)); + p->callback = callback; + p->param = param; + atomic_store(&p->tid, 0, memory_order_relaxed); +#else ThreadParam p; p.callback = callback; p.param = param; atomic_store(&p.tid, 0, memory_order_relaxed); +#endif int res; { // Ignore all allocations made by pthread_create: thread stack/TLS may be @@ -465,14 +488,22 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, // the linked list it's stored in doesn't even hold valid pointers to the // objects, the latter are calculated by obscure pointer arithmetic. ScopedInterceptorDisabler disabler; +#if SANITIZER_EMSCRIPTEN + res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, p); +#else res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); +#endif } if (res == 0) { int tid = ThreadCreate(GetCurrentThread(), IsStateDetached(detached)); CHECK_NE(tid, kMainTid); +#if SANITIZER_EMSCRIPTEN + atomic_store(&p->tid, tid, memory_order_release); +#else atomic_store(&p.tid, tid, memory_order_release); while (atomic_load(&p.tid, memory_order_acquire) != 0) internal_sched_yield(); +#endif } if (attr == &myattr) pthread_attr_destroy(&myattr); @@ -485,6 +516,7 @@ INTERCEPTOR(int, pthread_join, void *t, void **arg) { DEFINE_REAL_PTHREAD_FUNCTIONS +#if !SANITIZER_EMSCRIPTEN INTERCEPTOR(void, _exit, int status) { if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; REAL(_exit)(status); @@ -492,14 +524,14 @@ INTERCEPTOR(void, _exit, int status) { #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #include "sanitizer_common/sanitizer_signal_interceptors.inc" - -#endif // SANITIZER_POSIX +#endif namespace __lsan { void InitializeInterceptors() { // Fuchsia doesn't use interceptors that require any setup. #if !SANITIZER_FUCHSIA +#if !SANITIZER_EMSCRIPTEN InitializeSignalInterceptors(); INTERCEPT_FUNCTION(malloc); @@ -528,6 +560,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)) { @@ -540,3 +573,4 @@ void InitializeInterceptors() { } } // namespace __lsan +#endif // SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/lsan/lsan_linux.cpp b/compiler-rt/lib/lsan/lsan_linux.cpp index 47c2f21b5a6bc..63ae2c1a945b8 100644 --- a/compiler-rt/lib/lsan/lsan_linux.cpp +++ b/compiler-rt/lib/lsan/lsan_linux.cpp @@ -12,7 +12,7 @@ #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA +#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN #include "lsan_allocator.h" @@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {} } // namespace __lsan -#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA +#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h index 192e9392d494a..650cf99128d78 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h @@ -19,12 +19,15 @@ #ifndef SANITIZER_ERRNO_CODES_H #define SANITIZER_ERRNO_CODES_H +// XXX EMSCRIPTEN: use wasi errno codes, which is what our musl port now uses +#include <wasi/api.h> + namespace __sanitizer { -#define errno_ENOMEM 12 -#define errno_EBUSY 16 -#define errno_EINVAL 22 -#define errno_ENAMETOOLONG 36 +#define errno_ENOMEM __WASI_ERRNO_NOMEM +#define errno_EBUSY __WASI_ERRNO_BUSY +#define errno_EINVAL __WASI_ERRNO_INVAL +#define errno_ENAMETOOLONG __WASI_ERRNO_NAMETOOLONG // Those might not present or their value diff er on diff erent platforms. extern const int errno_EOWNERDEAD; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h index d0db0129d4af1..7fa8008589b63 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -189,7 +189,7 @@ typedef u64 OFF64_T; #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC typedef uptr operator_new_size_type; #else -# if defined(__s390__) && !defined(__s390x__) +# if defined(__s390__) && !defined(__s390x__) || SANITIZER_EMSCRIPTEN // Special case: 31-bit s390 has unsigned long as size_t. typedef unsigned long operator_new_size_type; # else diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 2e4d57d87f58e..ef0b0167fb3a6 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #include "sanitizer_common.h" #include "sanitizer_flags.h" @@ -104,9 +104,21 @@ extern struct ps_strings *__ps_strings; #define environ _environ #endif +#if SANITIZER_EMSCRIPTEN +#define weak __attribute__(__weak__) +#define hidden __attribute__((__visibility__("hidden"))) +#include <syscall.h> +#undef weak +#undef hidden +#include <emscripten/threading.h> +#include <math.h> +#include <wasi/api.h> +#include <wasi/wasi-helpers.h> +#endif + extern char **environ; -#if SANITIZER_LINUX +#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN // <linux/time.h> struct kernel_timeval { long tv_sec; @@ -193,7 +205,7 @@ ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); } // --------------- sanitizer_libc.h #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD -#if !SANITIZER_S390 +#if !SANITIZER_S390 && !SANITIZER_EMSCRIPTEN uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset) { #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS @@ -206,8 +218,9 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, offset / 4096); #endif } -#endif // !SANITIZER_S390 +#endif // !SANITIZER_S390 && !SANITIZER_NETBSD +#if !SANITIZER_EMSCRIPTEN uptr internal_munmap(void *addr, uptr length) { return internal_syscall(SYSCALL(munmap), (uptr)addr, length); } @@ -223,13 +236,18 @@ uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags, int internal_mprotect(void *addr, uptr length, int prot) { return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); } +#endif int internal_madvise(uptr addr, uptr length, int advice) { return internal_syscall(SYSCALL(madvise), addr, length, advice); } uptr internal_close(fd_t fd) { +#if SANITIZER_EMSCRIPTEN + return __wasi_fd_close(fd); +#else return internal_syscall(SYSCALL(close), fd); +#endif } uptr internal_open(const char *filename, int flags) { @@ -250,17 +268,35 @@ uptr internal_open(const char *filename, int flags, u32 mode) { } uptr internal_read(fd_t fd, void *buf, uptr count) { +#ifdef __EMSCRIPTEN__ + __wasi_iovec_t iov = { (uint8_t *)buf, count }; + size_t num; + if (__wasi_syscall_ret(__wasi_fd_read(fd, &iov, 1, &num))) { + return -1; + } + return num; +#else sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); return res; +#endif } uptr internal_write(fd_t fd, const void *buf, uptr count) { +#ifdef __EMSCRIPTEN__ + __wasi_ciovec_t iov = { (const uint8_t *)buf, count }; + size_t num; + if (__wasi_syscall_ret(__wasi_fd_write(fd, &iov, 1, &num))) { + return -1; + } + return num; +#else sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); return res; +#endif } uptr internal_ftruncate(fd_t fd, uptr size) { @@ -270,7 +306,7 @@ 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; @@ -419,7 +455,7 @@ uptr internal_dup(int oldfd) { } uptr internal_dup2(int oldfd, int newfd) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_EMSCRIPTEN return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0); #else return internal_syscall(SYSCALL(dup2), oldfd, newfd); @@ -456,26 +492,38 @@ uptr internal_rename(const char *oldpath, const char *newpath) { } uptr internal_sched_yield() { +#if SANITIZER_EMSCRIPTEN + return 0; +#else return internal_syscall(SYSCALL(sched_yield)); +#endif } void internal_usleep(u64 useconds) { +#if SANITIZER_EMSCRIPTEN + usleep(useconds); +#else struct timespec ts; ts.tv_sec = useconds / 1000000; ts.tv_nsec = (useconds % 1000000) * 1000; internal_syscall(SYSCALL(nanosleep), &ts, &ts); +#endif } +#if !SANITIZER_EMSCRIPTEN uptr internal_execve(const char *filename, char *const argv[], char *const envp[]) { return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, (uptr)envp); } +#endif // !SANITIZER_EMSCRIPTEN #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD #if !SANITIZER_NETBSD void internal__exit(int exitcode) { -#if SANITIZER_FREEBSD || SANITIZER_SOLARIS +#if SANITIZER_EMSCRIPTEN + __wasi_proc_exit(exitcode); +#elif SANITIZER_FREEBSD || SANITIZER_SOLARIS internal_syscall(SYSCALL(exit), exitcode); #else internal_syscall(SYSCALL(exit_group), exitcode); @@ -507,11 +555,14 @@ tid_t GetTid() { return Tid; #elif SANITIZER_SOLARIS return thr_self(); +#elif SANITIZER_EMSCRIPTEN + return (tid_t) pthread_self(); #else return internal_syscall(SYSCALL(gettid)); #endif } +#if !SANITIZER_EMSCRIPTEN int TgKill(pid_t pid, tid_t tid, int sig) { #if SANITIZER_LINUX return internal_syscall(SYSCALL(tgkill), pid, tid, sig); @@ -523,6 +574,7 @@ int TgKill(pid_t pid, tid_t tid, int sig) { #endif } #endif +#endif #if SANITIZER_GLIBC u64 NanoTime() { @@ -543,11 +595,19 @@ u64 NanoTime() { } #endif +#if SANITIZER_EMSCRIPTEN +int __clock_gettime(__sanitizer_clockid_t clk_id, void *tp); + +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + return __clock_gettime(clk_id, tp); +} +#endif + // Like getenv, but reads env directly from /proc (on Linux) or parses the // 'environ' array (on some others) and does not use libc. This function // should be called first inside __asan_init. const char *GetEnv(const char *name) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN if (::environ != 0) { uptr NameLen = internal_strlen(name); for (char **Env = ::environ; *Env != 0; Env++) { @@ -616,6 +676,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr, } #endif +#if !SANITIZER_EMSCRIPTEN static void GetArgsAndEnv(char ***argv, char ***envp) { #if SANITIZER_FREEBSD // On FreeBSD, retrieving the argument and environment arrays is done via the @@ -667,12 +728,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 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 @@ -683,6 +748,8 @@ void FutexWake(atomic_uint32_t *p, u32 count) { _umtx_op(p, UMTX_OP_WAKE, count, 0, 0); # elif SANITIZER_NETBSD /* 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 @@ -714,11 +781,13 @@ struct linux_dirent { #endif #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_EMSCRIPTEN // Syscall wrappers. uptr internal_ptrace(int request, int pid, void *addr, void *data) { return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, (uptr)data); } +#endif uptr internal_waitpid(int pid, int *status, int options) { return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, @@ -752,7 +821,12 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { } uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { +#if SANITIZER_EMSCRIPTEN + __wasi_filesize_t result; + return __wasi_syscall_ret(__wasi_fd_seek(fd, offset, whence, &result)) ? -1 : result; +#else return internal_syscall(SYSCALL(lseek), fd, offset, whence); +#endif } #if SANITIZER_LINUX @@ -761,12 +835,17 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { } #endif +#if !SANITIZER_EMSCRIPTEN uptr internal_sigaltstack(const void *ss, void *oss) { return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); } +#endif int internal_fork() { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_EMSCRIPTEN + Report("fork not supported on emscripten\n"); + return -1; +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(clone), SIGCHLD, 0); #else return internal_syscall(SYSCALL(fork)); @@ -861,6 +940,8 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { #if SANITIZER_FREEBSD return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); +#elif SANITIZER_EMSCRIPTEN + return NULL; #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; @@ -910,7 +991,7 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { #endif #endif // !SANITIZER_SOLARIS -#if !SANITIZER_NETBSD +#if !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN // ThreadLister implementation. ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { char task_directory_path[80]; @@ -1091,19 +1172,23 @@ uptr GetPageSize() { int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); CHECK_EQ(rv, 0); return (uptr)pz; -#elif SANITIZER_USE_GETAUXVAL - return getauxval(AT_PAGESZ); #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif } #endif // !SANITIZER_ANDROID +#if SANITIZER_EMSCRIPTEN +extern "C" uptr emscripten_get_module_name(char *buf, uptr buf_len); +#endif + uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { #if SANITIZER_SOLARIS const char *default_module_name = getexecname(); CHECK_NE(default_module_name, NULL); return internal_snprintf(buf, buf_len, "%s", default_module_name); +#elif SANITIZER_EMSCRIPTEN + return emscripten_get_module_name(buf, buf_len); #else #if SANITIZER_FREEBSD || SANITIZER_NETBSD #if SANITIZER_FREEBSD @@ -2138,6 +2223,9 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.pc; *bp = ucontext->uc_mcontext.r30; *sp = ucontext->uc_mcontext.r29; +#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 ebd60e0b10f27..dd65b8245978f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_platform_limits_freebsd.h" diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index 8de765cf6669d..0ee225f32d39d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -14,7 +14,7 @@ #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \ - !(defined(__sun__) && defined(__svr4__)) + !(defined(__sun__) && defined(__svr4__)) && !defined(__EMSCRIPTEN__) # error "This operating system is not supported" #endif @@ -116,9 +116,15 @@ # define SANITIZER_FUCHSIA 0 #endif +#if defined(__EMSCRIPTEN__) +# define SANITIZER_EMSCRIPTEN 1 +#else +# define SANITIZER_EMSCRIPTEN 0 +#endif + #define SANITIZER_POSIX \ (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ - SANITIZER_NETBSD || SANITIZER_SOLARIS) + SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN) #if __LP64__ || defined(_WIN64) # define SANITIZER_WORDSIZE 64 @@ -291,6 +297,11 @@ # define SANITIZER_SIGN_EXTENDED_ADDRESSES 0 #endif +// Emscripten emulates the canonical linux syscall set. +#if !defined SANITIZER_USES_CANONICAL_LINUX_SYSCALLS && SANITIZER_EMSCRIPTEN +# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 1 +#endif + // The AArch64 and RISC-V linux ports use the canonical syscall set as // mandated by the upstream linux community for all new ports. Other ports // may still use legacy syscalls. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 14610f2df78df..91080cca06e37 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -132,12 +132,24 @@ #define SI_POSIX_NOT_MAC 0 #endif +#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN +# define SI_POSIX_NOT_EMSCRIPTEN 1 +#else +# define SI_POSIX_NOT_EMSCRIPTEN 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_FREEBSD #define SI_LINUX_NOT_FREEBSD 1 #else #define SI_LINUX_NOT_FREEBSD 0 #endif +#if SANITIZER_EMSCRIPTEN +# define SI_EMSCRIPTEN 1 +#else +# define SI_EMSCRIPTEN 0 +#endif + #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA @@ -263,7 +275,7 @@ #define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX #define SANITIZER_INTERCEPT_SYSMSG SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX -#define SANITIZER_INTERCEPT_IOCTL SI_POSIX +#define SANITIZER_INTERCEPT_IOCTL SI_POSIX && !SI_EMSCRIPTEN #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX #define SANITIZER_INTERCEPT_READDIR SI_POSIX @@ -301,7 +313,7 @@ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS -#define SANITIZER_INTERCEPT_STRERROR SI_POSIX +#define SANITIZER_INTERCEPT_STRERROR SI_POSIX_NOT_EMSCRIPTEN #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR \ @@ -482,7 +494,7 @@ #define SANITIZER_INTERCEPT_MMAP SI_POSIX #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID || SI_SOLARIS -#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID) +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID || 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 32b8f47ed6338..269b43c17f5fd 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -11,7 +11,7 @@ // Sizes and layouts of platform-specific POSIX data structures. //===----------------------------------------------------------------------===// -#if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__) // Tests in this file assume that off_t-dependent data structures match the // libc ABI. For example, struct dirent here is what readdir() function (as // exported from libc) returns, and not the user-facing "dirent", which @@ -23,7 +23,7 @@ // Must go after undef _FILE_OFFSET_BITS. #include "sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_MAC +#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN // Must go after undef _FILE_OFFSET_BITS. #include "sanitizer_glibc_version.h" @@ -59,7 +59,7 @@ #include <net/route.h> #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN #include <sys/mount.h> #include <sys/timeb.h> #include <utmpx.h> @@ -159,7 +159,7 @@ typedef struct user_fpregs elf_fpregset_t; #include <sys/vfs.h> #include <sys/epoll.h> #include <linux/capability.h> -#else +#elif !SANITIZER_EMSCRIPTEN #include <fstab.h> #endif // SANITIZER_LINUX @@ -212,7 +212,7 @@ namespace __sanitizer { unsigned struct_fstab_sz = sizeof(struct fstab); #endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || // SANITIZER_MAC -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN unsigned struct_statfs_sz = sizeof(struct statfs); unsigned struct_sockaddr_sz = sizeof(struct sockaddr); @@ -423,7 +423,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); @@ -504,15 +507,18 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); #endif // SANITIZER_GLIBC -#if !SANITIZER_ANDROID && !SANITIZER_MAC +#if !SANITIZER_ANDROID && !SANITIZER_MAC && !SANITIZER_EMSCRIPTEN unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); #endif +#if !SANITIZER_EMSCRIPTEN const unsigned long __sanitizer_bufsiz = BUFSIZ; +#endif const unsigned IOCTL_NOT_PRESENT = 0; +#if !SANITIZER_EMSCRIPTEN unsigned IOCTL_FIOASYNC = FIOASYNC; unsigned IOCTL_FIOCLEX = FIOCLEX; unsigned IOCTL_FIOGETOWN = FIOGETOWN; @@ -561,6 +567,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); @@ -1054,6 +1061,7 @@ CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); #endif COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +#if !SANITIZER_EMSCRIPTEN CHECK_SIZE_AND_OFFSET(dirent, d_ino); #if SANITIZER_MAC CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); @@ -1063,6 +1071,7 @@ CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); CHECK_SIZE_AND_OFFSET(dirent, d_off); #endif CHECK_SIZE_AND_OFFSET(dirent, d_reclen); +#endif // !SANITIZER_EMSCRIPTEN #if SANITIZER_LINUX && !SANITIZER_ANDROID COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); @@ -1082,6 +1091,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)); @@ -1096,6 +1106,7 @@ CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); #if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); #endif +#endif // !SANITIZER_EMSCRIPTEN #if SANITIZER_LINUX CHECK_TYPE_SIZE(__sysctl_args); @@ -1149,7 +1160,9 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); #endif +#if !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(ether_addr); +#endif #if SANITIZER_GLIBC || SANITIZER_FREEBSD CHECK_TYPE_SIZE(ipc_perm); @@ -1187,7 +1200,7 @@ CHECK_TYPE_SIZE(clock_t); CHECK_TYPE_SIZE(clockid_t); #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(ifaddrs); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); @@ -1217,7 +1230,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 4472b6efa963f..0884278a8407e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -14,7 +14,7 @@ #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H #define SANITIZER_PLATFORM_LIMITS_POSIX_H -#if SANITIZER_LINUX || SANITIZER_MAC +#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" @@ -430,7 +430,8 @@ struct __sanitizer_file_handle { }; #endif -#if SANITIZER_MAC +// These fields are not actually pointers, and so wasm64 must use unsigned and not uptr for them +#if SANITIZER_MAC || SANITIZER_EMSCRIPTEN struct __sanitizer_msghdr { void *msg_name; unsigned msg_namelen; @@ -509,7 +510,7 @@ typedef long long __sanitizer_clock_t; typedef long __sanitizer_clock_t; #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN typedef int __sanitizer_clockid_t; #endif @@ -562,6 +563,8 @@ struct __sanitizer_sigset_t { // The size is determined by looking at sizeof of real sigset_t on linux. uptr val[128 / sizeof(uptr)]; }; +#elif SANITIZER_EMSCRIPTEN +typedef unsigned long __sanitizer_sigset_t; #endif struct __sanitizer_siginfo { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp index f8457a6aac413..4269fed630051 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp @@ -92,11 +92,17 @@ 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); +#endif } +#ifndef SANITIZER_EMSCRIPTEN + // Emscripten's fake mmap doesn't support partial unmapping uptr end = res + size; if (end != map_end) UnmapOrDie((void*)end, map_end - end); +#endif return (void*)res; } @@ -220,6 +226,16 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1, return (end1 < start2) || (end2 < start1); } +#if SANITIZER_EMSCRIPTEN +bool MemoryRangeIsAvailable(uptr /*range_start*/, uptr /*range_end*/) { + // TODO: actually implement this. + return true; +} + +void DumpProcessMap() { + Report("Cannot dump memory map on emscripten"); +} +#else // FIXME: this is thread-unsafe, but should not cause problems most of the time. // When the shadow is mapped only a single thread usually exists (plus maybe // several worker threads on Mac, which aren't expected to map big chunks of @@ -254,6 +270,7 @@ void DumpProcessMap() { UnmapOrDie(filename, kBufSize); } #endif +#endif const char *GetPwd() { return GetEnv("PWD"); @@ -274,6 +291,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<char> buff(kMaxPathLength); MemoryMappedSegment segment(buff.data(), buff.size()); @@ -285,6 +306,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 eed02ce4f6aa6..6fef032f542bb 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -209,7 +209,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); @@ -269,6 +271,11 @@ bool SignalContext::IsStackOverflow() const { #endif // SANITIZER_GO bool IsAccessibleMemoryRange(uptr beg, uptr size) { +#if SANITIZER_EMSCRIPTEN + // Avoid pulling in __sys_pipe for the trick below, which doesn't work on + // WebAssembly anyways because there are no memory protections. + return true; +#else uptr page_size = GetPageSizeCached(); // Checking too large memory ranges is slow. CHECK_LT(size, page_size * 10); @@ -288,6 +295,7 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) { internal_close(sock_pair[0]); internal_close(sock_pair[1]); return result; +#endif // SANITIZER_EMSCRIPTEN } void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { @@ -295,7 +303,9 @@ void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { // to read the file mappings from /proc/self/maps. Luckily, neither the // process will be able to load additional libraries, so it's fine to use the // cached mappings. +#ifndef SANITIZER_EMSCRIPTEN MemoryMappingLayout::CacheMemoryMappings(); +#endif } static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp index 37e9e6dd08d7b..87c25b7e64bf6 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp @@ -52,9 +52,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; @@ -65,8 +67,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 aebd504669d2d..197f26feb2f0d 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_MAC +#if SANITIZER_MAC || 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 2d1c03f732217..e79ceffe33c24 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -103,9 +103,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_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index 5f6e4cc3180e9..b39b4d8400fe7 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_POSIX +#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_file.h" diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp index ac855c8be1c86..8a796709ef2d5 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -40,7 +40,21 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info, } #endif -#if !SANITIZER_FUCHSIA +#if SANITIZER_EMSCRIPTEN +#include <emscripten/em_asm.h> + +static inline bool ReportSupportsColors() { + return !!EM_ASM_INT({ + var setting = Module['printWithColors']; + if (setting != null) { + return setting; + } else { + return ENVIRONMENT_IS_NODE && process.stderr.isTTY; + } + }); +} + +#elif !SANITIZER_FUCHSIA bool ReportFile::SupportsColors() { SpinMutexLock l(mu); @@ -57,7 +71,7 @@ static inline bool ReportSupportsColors() { // Fuchsia's logs always go through post-processing that handles colorization. static inline bool ReportSupportsColors() { return true; } -#endif // !SANITIZER_FUCHSIA +#endif // SANITIZER_EMSCRIPTEN, !SANITIZER_FUCHSIA bool ColorizeReports() { // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc index 8829985b5b07f..ba7ed46f861cc 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -13,7 +13,7 @@ // NetBSD uses libc calls directly #if !SANITIZER_NETBSD -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # define SYSCALL(name) SYS_ ## name #else # define SYSCALL(name) __NR_ ## name diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index 846cd89ee19f8..4e0c2bcf0e65f 100644 --- a/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -20,11 +20,6 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use", "nullability-assign") -UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow") -UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset", - "pointer-overflow") -UBSAN_CHECK(NullptrAfterNonZeroOffset, "nullptr-after-nonzero-offset", - "pointer-overflow") UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow") UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment") UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment") diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cpp b/compiler-rt/lib/ubsan/ubsan_diag.cpp index 8de51bc187701..adc2765562c7f 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cpp +++ b/compiler-rt/lib/ubsan/ubsan_diag.cpp @@ -408,7 +408,7 @@ static const char *kSuppressionTypes[] = { void __ubsan::InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) + suppression_ctx = new (suppression_placeholder) // NOLINT SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); } diff --git a/compiler-rt/lib/ubsan/ubsan_flags.cpp b/compiler-rt/lib/ubsan/ubsan_flags.cpp index 25cefd46ce27c..d5463b1fc8607 100644 --- a/compiler-rt/lib/ubsan/ubsan_flags.cpp +++ b/compiler-rt/lib/ubsan/ubsan_flags.cpp @@ -19,6 +19,11 @@ #include <stdlib.h> +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include <emscripten/em_asm.h> +#endif + namespace __ubsan { static const char *GetFlag(const char *flag) { @@ -50,7 +55,12 @@ void InitializeFlags() { { CommonFlags cf; cf.CopyFrom(*common_flags()); + cf.print_summary = false; +#if !SANITIZER_EMSCRIPTEN + // getenv on emscripten uses malloc, which we can't when using some sanitizers. + // You can't run external symbolizers anyway. cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH"); +#endif OverrideCommonFlags(cf); } @@ -64,7 +74,23 @@ void InitializeFlags() { // Override from user-specified string. parser.ParseString(__ubsan_default_options()); // Override from environment variable. +#if SANITIZER_EMSCRIPTEN +#ifdef __wasm64__ + // FIXME: support UBSAN in wasm64. + abort(); +#else + char *options = (char*) EM_ASM_INT({ + return withBuiltinMalloc(function () { + return allocateUTF8(Module['UBSAN_OPTIONS'] || 0); + }); + }); + parser.ParseString(options); + emscripten_builtin_free(options); +#endif +#else parser.ParseStringFromEnv("UBSAN_OPTIONS"); +#endif // SANITIZER_EMSCRIPTEN + InitializeCommonFlags(); if (Verbosity()) ReportUnrecognizedFlags(); diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp index e201e6bba2207..b070a378c0d47 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -766,33 +766,14 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data, ValueHandle Result, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - ErrorType ET; - - if (Base == 0 && Result == 0) - ET = ErrorType::NullptrWithOffset; - else if (Base == 0 && Result != 0) - ET = ErrorType::NullptrWithNonZeroOffset; - else if (Base != 0 && Result == 0) - ET = ErrorType::NullptrAfterNonZeroOffset; - else - ET = ErrorType::PointerOverflow; + ErrorType ET = ErrorType::PointerOverflow; if (ignoreReport(Loc, Opts, ET)) return; ScopedReport R(Opts, Loc, ET); - if (ET == ErrorType::NullptrWithOffset) { - Diag(Loc, DL_Error, ET, "applying zero offset to null pointer"); - } else if (ET == ErrorType::NullptrWithNonZeroOffset) { - Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer") - << Result; - } else if (ET == ErrorType::NullptrAfterNonZeroOffset) { - Diag( - Loc, DL_Error, ET, - "applying non-zero offset to non-null pointer %0 produced null pointer") - << (void *)Base; - } else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { + if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { if (Base > Result) Diag(Loc, DL_Error, ET, "addition of unsigned offset to %0 overflowed to %1") diff --git a/compiler-rt/lib/ubsan/ubsan_platform.h b/compiler-rt/lib/ubsan/ubsan_platform.h index d2cc2e10bd2f0..252536f26a80f 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(__Fuchsia__) || defined(__EMSCRIPTEN__) #define CAN_SANITIZE_UB 1 #else # define CAN_SANITIZE_UB 0 diff --git a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp index 2c91db8ca3974..8d980e1a26391 100644 --- a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp +++ b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp @@ -26,7 +26,7 @@ // debuggerd handler, but before the ART handler. // * Interceptors don't work at all when ubsan runtime is loaded late, ex. when // it is part of an APK that does not use wrap.sh method. -#if SANITIZER_FUCHSIA || SANITIZER_ANDROID +#if SANITIZER_FUCHSIA || SANITIZER_ANDROID || SANITIZER_EMSCRIPTEN namespace __ubsan { void InitializeDeadlySignals() {} @@ -45,9 +45,8 @@ namespace __ubsan { static void OnStackUnwind(const SignalContext &sig, const void *, BufferedStackTrace *stack) { - ubsan_GetStackTrace(stack, kStackTraceMax, - StackTrace::GetNextInstructionPc(sig.pc), sig.bp, - sig.context, common_flags()->fast_unwind_on_fatal); + ubsan_GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context, + common_flags()->fast_unwind_on_fatal); } static void UBsanOnDeadlySignal(int signo, void *siginfo, void *context) { diff --git a/libcxx/include/__config b/libcxx/include/__config index 458d0c1b897af..dec8d499850c8 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1,3 +1,6 @@ +// XXX EMSCRIPTEN: macros that would ordinarily be added from __config_site.in +#define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS + // -*- C++ -*- //===----------------------------------------------------------------------===// // @@ -95,7 +98,8 @@ // Previously libc++ used "unsigned int" exclusively. # define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION // Unstable attempt to provide a more optimized std::function -# define _LIBCPP_ABI_OPTIMIZED_FUNCTION +// XXX EMSCRIPTEN https://github.com/emscripten-core/emscripten/issues/11022 +//# define _LIBCPP_ABI_OPTIMIZED_FUNCTION // All the regex constants must be distinct and nonzero. # define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO // Use raw pointers, not wrapped ones, for std::span's iterator type. @@ -388,7 +392,7 @@ // constructor *must* be "/dev/urandom" -- anything else is an error. #if defined(__OpenBSD__) || defined(__APPLE__) # define _LIBCPP_USING_ARC4_RANDOM -#elif defined(__wasi__) +#elif defined(__wasi__) || defined(__EMSCRIPTEN__) # define _LIBCPP_USING_GETENTROPY #elif defined(__Fuchsia__) # define _LIBCPP_USING_FUCHSIA_CPRNG @@ -1147,6 +1151,7 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container( defined(__sun__) || \ defined(__MVS__) || \ defined(_AIX) + defined(__EMSCRIPTEN__) || \ # define _LIBCPP_HAS_THREAD_API_PTHREAD # elif defined(__Fuchsia__) // TODO(44575): Switch to C11 thread API when possible. diff --git a/libcxx/include/locale b/libcxx/include/locale index 7c2d2361f7513..12ba1c531d416 100644 --- a/libcxx/include/locale +++ b/libcxx/include/locale @@ -204,9 +204,9 @@ template <class charT> class messages_byname; #include <streambuf> #include <version> -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) // Most unix variants have catopen. These are the specific ones that don't. -# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) +# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__) // XXX Emscripten catopen always returns -1 # define _LIBCPP_HAS_CATOPEN 1 # include <nl_types.h> # endif diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo index af82175487706..81bdf44c1c6ea 100644 --- a/libcxx/include/typeinfo +++ b/libcxx/include/typeinfo @@ -330,6 +330,9 @@ public: return __impl::__hash(__type_name); } + // XXX Emscripten: adding `always_inline` fixes + // https://github.com/emscripten-core/emscripten/issues/13330 + __attribute__((always_inline)) _LIBCPP_INLINE_VISIBILITY bool operator==(const type_info& __arg) const _NOEXCEPT { diff --git a/libcxx/src/include/config_elast.h b/libcxx/src/include/config_elast.h index 0ed53a3b20d12..13e1624a97ee3 100644 --- a/libcxx/src/include/config_elast.h +++ b/libcxx/src/include/config_elast.h @@ -33,6 +33,8 @@ #define _LIBCPP_ELAST 4095 #elif defined(__APPLE__) // No _LIBCPP_ELAST needed on Apple +#elif defined(__EMSCRIPTEN__) // XXX EMSCRIPTEN added ELAST value +#define _LIBCPP_ELAST 256 #elif defined(__sun__) #define _LIBCPP_ELAST ESTALE #elif defined(__MVS__) diff --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp index 0a9bee4e39a41..9eab31f95c10f 100644 --- a/libcxx/src/new.cpp +++ b/libcxx/src/new.cpp @@ -74,8 +74,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC else #ifndef _LIBCPP_NO_EXCEPTIONS throw std::bad_alloc(); +#else +#ifdef __EMSCRIPTEN__ + // Abort here so that when exceptions are disabled, we do not just + // return 0 when malloc returns 0. + // We could also do this with set_new_handler, but that adds a + // global constructor and a table entry, overhead that we can avoid + // by doing it this way. + abort(); #else break; +#endif #endif } return p; diff --git a/libcxx/src/support/runtime/exception_fallback.ipp b/libcxx/src/support/runtime/exception_fallback.ipp index 67ebde3061ad8..c85b2586858ca 100644 --- a/libcxx/src/support/runtime/exception_fallback.ipp +++ b/libcxx/src/support/runtime/exception_fallback.ipp @@ -49,6 +49,7 @@ get_terminate() noexcept return __libcpp_atomic_load(&__terminate_handler); } +#ifndef __EMSCRIPTEN__ // We provide this in JS _LIBCPP_NORETURN void terminate() noexcept @@ -71,7 +72,9 @@ terminate() noexcept } #endif // _LIBCPP_NO_EXCEPTIONS } +#endif // !__EMSCRIPTEN__ +#if !defined(__EMSCRIPTEN__) bool uncaught_exception() noexcept { return uncaught_exceptions() > 0; } int uncaught_exceptions() noexcept @@ -80,6 +83,7 @@ int uncaught_exceptions() noexcept fprintf(stderr, "uncaught_exceptions not yet implemented\n"); ::abort(); } +#endif // !__EMSCRIPTEN__ exception::~exception() noexcept diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h index eaa324dc6867e..9e729b007a5f2 100644 --- a/libcxxabi/include/cxxabi.h +++ b/libcxxabi/include/cxxabi.h @@ -40,20 +40,24 @@ extern "C" { // 2.4.2 Allocating the Exception Object extern _LIBCXXABI_FUNC_VIS void * -__cxa_allocate_exception(size_t thrown_size) throw(); +__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void -__cxa_free_exception(void *thrown_exception) throw(); +__cxa_free_exception(void *thrown_exception) _NOEXCEPT; // 2.4.3 Throwing the Exception Object extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw(void *thrown_exception, std::type_info *tinfo, +#ifdef __USING_WASM_EXCEPTIONS__ + void *(*dest)(void *)); +#else void (*dest)(void *)); +#endif // 2.5.3 Exception Handlers extern _LIBCXXABI_FUNC_VIS void * -__cxa_get_exception_ptr(void *exceptionObject) throw(); +__cxa_get_exception_ptr(void *exceptionObject) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void * -__cxa_begin_catch(void *exceptionObject) throw(); +__cxa_begin_catch(void *exceptionObject) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch(); #if defined(_LIBCXXABI_ARM_EHABI) extern _LIBCXXABI_FUNC_VIS bool @@ -148,17 +152,17 @@ extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name, // Apple additions to support C++ 0x exception_ptr class // These are primitives to wrap a smart pointer around an exception object -extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw(); +extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void __cxa_rethrow_primary_exception(void *primary_exception); extern _LIBCXXABI_FUNC_VIS void -__cxa_increment_exception_refcount(void *primary_exception) throw(); +__cxa_increment_exception_refcount(void *primary_exception) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void -__cxa_decrement_exception_refcount(void *primary_exception) throw(); +__cxa_decrement_exception_refcount(void *primary_exception) _NOEXCEPT; // Apple extension to support std::uncaught_exception() -extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw(); -extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw(); +extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() _NOEXCEPT; +extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() _NOEXCEPT; #if defined(__linux__) || defined(__Fuchsia__) // Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI. diff --git a/libcxxabi/src/abort_message.cpp b/libcxxabi/src/abort_message.cpp index 859a5031b93fe..0cbce088228c7 100644 --- a/libcxxabi/src/abort_message.cpp +++ b/libcxxabi/src/abort_message.cpp @@ -33,12 +33,21 @@ void abort_message(const char* format, ...) // formatting into the variable-sized buffer fails. #if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL) { +#if defined(__EMSCRIPTEN__) && defined(NDEBUG) + // Just trap in a non-debug build. These internal libcxxabi assertions are + // very rare, and it's not worth linking in vfprintf stdio support or + // even minimal logging for them, as we'll have a proper call stack, which + // will show a call into "abort_message", and can help debugging. (In a + // debug build that won't be inlined.) + 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 36388d50dad20..a92997b9031f9 100644 --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -180,7 +180,7 @@ extern "C" { // object. Zero-fill the object. If memory can't be allocated, call // std::terminate. Return a pointer to the memory to be used for the // user's exception object. -void *__cxa_allocate_exception(size_t thrown_size) throw() { +void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); // Allocate extra space before the __cxa_exception header to ensure the @@ -198,7 +198,7 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() { // Free a __cxa_exception object allocated with __cxa_allocate_exception. -void __cxa_free_exception(void *thrown_object) throw() { +void __cxa_free_exception(void *thrown_object) _NOEXCEPT { // Compute the size of the padding before the header. size_t header_offset = get_cxa_exception_offset(); char *raw_buffer = @@ -254,7 +254,12 @@ will call terminate, assuming that there was no handler for the exception. */ void +#ifdef __USING_WASM_EXCEPTIONS__ +// In wasm, destructors return their argument +__cxa_throw(void *thrown_object, std::type_info *tinfo, void *(*dest)(void *)) { +#else __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { +#endif __cxa_eh_globals *globals = __cxa_get_globals(); __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -292,7 +297,7 @@ The adjusted pointer is computed by the personality routine during phase 1 Requires: exception is native */ -void *__cxa_get_exception_ptr(void *unwind_exception) throw() { +void *__cxa_get_exception_ptr(void *unwind_exception) _NOEXCEPT { #if defined(_LIBCXXABI_ARM_EHABI) return reinterpret_cast<void*>( static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); @@ -307,7 +312,7 @@ void *__cxa_get_exception_ptr(void *unwind_exception) throw() { The routine to be called before the cleanup. This will save __cxa_exception in __cxa_eh_globals, so that __cxa_end_cleanup() can recover later. */ -bool __cxa_begin_cleanup(void *unwind_arg) throw() { +bool __cxa_begin_cleanup(void *unwind_arg) _NOEXCEPT { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); __cxa_eh_globals* globals = __cxa_get_globals(); __cxa_exception* exception_header = @@ -426,7 +431,7 @@ to terminate or unexpected during unwinding. _Unwind_Exception and return a pointer to that. */ void* -__cxa_begin_catch(void* unwind_arg) throw() +__cxa_begin_catch(void* unwind_arg) _NOEXCEPT { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); bool native_exception = __isOurExceptionClass(unwind_exception); @@ -634,7 +639,7 @@ void __cxa_rethrow() { Requires: If thrown_object is not NULL, it is a native exception. */ void -__cxa_increment_exception_refcount(void *thrown_object) throw() { +__cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -651,7 +656,7 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() { Requires: If thrown_object is not NULL, it is a native exception. */ _LIBCXXABI_NO_CFI -void __cxa_decrement_exception_refcount(void *thrown_object) throw() { +void __cxa_decrement_exception_refcount(void *thrown_object) _NOEXCEPT { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -674,7 +679,7 @@ void __cxa_decrement_exception_refcount(void *thrown_object) throw() { been no exceptions thrown, ever, on this thread, we can return NULL without the need to allocate the exception-handling globals. */ -void *__cxa_current_primary_exception() throw() { +void *__cxa_current_primary_exception() _NOEXCEPT { // get the current exception __cxa_eh_globals* globals = __cxa_get_globals_fast(); if (NULL == globals) @@ -746,10 +751,10 @@ __cxa_rethrow_primary_exception(void* thrown_object) } bool -__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } +__cxa_uncaught_exception() _NOEXCEPT { return __cxa_uncaught_exceptions() != 0; } unsigned int -__cxa_uncaught_exceptions() throw() +__cxa_uncaught_exceptions() _NOEXCEPT { // This does not report foreign exceptions in flight __cxa_eh_globals* globals = __cxa_get_globals_fast(); diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h index 7a32fb653b076..4d1770c31457d 100644 --- a/libcxxabi/src/cxa_exception.h +++ b/libcxxabi/src/cxa_exception.h @@ -19,6 +19,25 @@ namespace __cxxabiv1 { +#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__ + +struct _LIBCXXABI_HIDDEN __cxa_exception { + size_t referenceCount; + std::type_info *exceptionType; + 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 multipl 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++ @@ -43,7 +62,12 @@ struct _LIBCXXABI_HIDDEN __cxa_exception { // Manage the exception object itself. std::type_info *exceptionType; +#ifdef __USING_WASM_EXCEPTIONS__ + // In wasm, destructors return their argument + void *(*exceptionDestructor)(void *); +#else void (*exceptionDestructor)(void *); +#endif std::unexpected_handler unexpectedHandler; std::terminate_handler terminateHandler; @@ -159,6 +183,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 // !__USING_EMSCRIPTEN_EXCEPTIONS__ + } // namespace __cxxabiv1 #endif // _CXA_EXCEPTION_H diff --git a/libcxxabi/src/cxa_handlers.cpp b/libcxxabi/src/cxa_handlers.cpp index 344250dde0c7e..07913fba397e6 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(__USING_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_personality.cpp b/libcxxabi/src/cxa_personality.cpp index f6e135f137c09..93ba2bf07d1e8 100644 --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -22,6 +22,8 @@ #include "private_typeinfo.h" #include "unwind.h" +#define __USING_SJLJ_OR_WASM_EXCEPTIONS__ (__USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__) + #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) #include <windows.h> #include <winnt.h> @@ -61,7 +63,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, +------------------+--+-----+-----+------------------------+--------------------------+ | callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table | +---------------------+-----------+---------------------------------------------------+ -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------+-----------+------------------------------------------------+ | Beginning of Call Site Table The current ip lies within the | | ... (start, length) range of one of these | @@ -75,7 +77,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, | +-------------+---------------------------------+------------------------------+ | | ... | +----------------------------------------------------------------------------------+ -#else // __USING_SJLJ_EXCEPTIONS__ +#else // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------+-----------+------------------------------------------------+ | Beginning of Call Site Table The current ip is a 1-based index into | | ... this table. Or it is -1 meaning no | @@ -88,7 +90,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, | +-------------+---------------------------------+------------------------------+ | | ... | +----------------------------------------------------------------------------------+ -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------------------------------------------------------+ | Beginning of Action Table ttypeIndex == 0 : cleanup | | ... ttypeIndex > 0 : catch | @@ -538,7 +540,7 @@ void set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, const scan_results& results) { -#if defined(__USING_SJLJ_EXCEPTIONS__) +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ #define __builtin_eh_return_data_regno(regno) regno #elif defined(__ibmxl__) // IBM xlclang++ compiler does not support __builtin_eh_return_data_regno. @@ -633,7 +635,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Get beginning current frame's code (as defined by the // emitted dwarf code) uintptr_t funcStart = _Unwind_GetRegionStart(context); -#ifdef __USING_SJLJ_EXCEPTIONS__ +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ if (ip == uintptr_t(-1)) { // no action @@ -643,9 +645,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, else if (ip == 0) call_terminate(native_exception, unwind_exception); // ip is 1-based index into call site table -#else // !__USING_SJLJ_EXCEPTIONS__ +#else // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ uintptr_t ipOffset = ip - funcStart; -#endif // !defined(_USING_SLJL_EXCEPTIONS__) +#endif // !defined(__USING_SJLJ_OR_WASM_EXCEPTIONS__) const uint8_t* classInfo = NULL; // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding // dwarf emission @@ -667,8 +669,8 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Walk call-site table looking for range that // includes current PC. uint8_t callSiteEncoding = *lsda++; -#ifdef __USING_SJLJ_EXCEPTIONS__ - (void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ + (void)callSiteEncoding; // When using SjLj/Wasm exceptions, callSiteEncoding is never used #endif uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda)); const uint8_t* callSiteTableStart = lsda; @@ -678,7 +680,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, while (callSitePtr < callSiteTableEnd) { // There is one entry per call site. -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ // The call sites are non-overlapping in [start, start+length) // The call sites are ordered in increasing value of start uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); @@ -686,15 +688,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); uintptr_t actionEntry = readULEB128(&callSitePtr); if ((start <= ipOffset) && (ipOffset < (start + length))) -#else // __USING_SJLJ_EXCEPTIONS__ +#else // __USING_SJLJ_OR_WASM_EXCEPTIONS__ // ip is 1-based index into this table uintptr_t landingPad = readULEB128(&callSitePtr); uintptr_t actionEntry = readULEB128(&callSitePtr); if (--ip == 0) -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_OR_WASM_EXCEPTIONS__ { // Found the call site containing ip. -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ if (landingPad == 0) { // No handler here @@ -702,9 +704,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, return; } landingPad = (uintptr_t)lpStart + landingPad; -#else // __USING_SJLJ_EXCEPTIONS__ +#else // __USING_SJLJ_OR_WASM_EXCEPTIONS__ ++landingPad; -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_OR_WASM_EXCEPTIONS__ results.landingPad = landingPad; if (actionEntry == 0) { @@ -796,8 +798,6 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, { // Native exception caught by exception // specification. - assert(actions & _UA_SEARCH_PHASE); - results.ttypeIndex = ttypeIndex; results.actionRecord = actionRecord; results.adjustedPtr = adjustedPtr; results.reason = _URC_HANDLER_FOUND; @@ -832,7 +832,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, action += actionOffset; } // there is no break out of this loop, only return } -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ else if (ipOffset < start) { // There is no call site for this ip @@ -840,7 +840,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Possible stack corruption. call_terminate(native_exception, unwind_exception); } -#endif // !__USING_SJLJ_EXCEPTIONS__ +#endif // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ } // there might be some tricky cases which break out of this loop // It is possible that no eh table entry specify how to handle @@ -897,7 +897,9 @@ _UA_CLEANUP_PHASE */ #if !defined(_LIBCXXABI_ARM_EHABI) -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) +#ifdef __USING_WASM_EXCEPTIONS__ +_Unwind_Reason_Code __gxx_personality_wasm0 +#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) static _Unwind_Reason_Code __gxx_personality_imp #else _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code @@ -979,6 +981,16 @@ __gxx_personality_v0 exception_header->catchTemp = 0; #endif } +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm uses only one phase in _UA_CLEANUP_PHASE, so we should set + // these here. + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + exception_header->handlerSwitchValue = static_cast<int>(results.ttypeIndex); + exception_header->actionRecord = results.actionRecord; + exception_header->languageSpecificData = results.languageSpecificData; + exception_header->catchTemp = reinterpret_cast<void*>(results.landingPad); + exception_header->adjustedPtr = results.adjustedPtr; +#endif return _URC_INSTALL_CONTEXT; } diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp index 665f9e55694ab..dcf283ceb1dff 100644 --- a/libcxxabi/src/cxa_thread_atexit.cpp +++ b/libcxxabi/src/cxa_thread_atexit.cpp @@ -112,9 +112,14 @@ extern "C" { #ifdef HAVE___CXA_THREAD_ATEXIT_IMPL return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); #else +#ifndef __EMSCRIPTEN__ + // Emscripten doesn't fully support weak undefined symbols yet + // https://github.com/emscripten-core/emscripten/issues/12819 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; diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index e1086661c019d..8ee2e7607c7da 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -1323,4 +1323,35 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info, use_strcmp); } +// XXX EMSCRIPTEN + +#ifndef __USING_WASM_EXCEPTIONS__ + +// These functions are used by the emscripten-style exception handling +// mechanism. +// Note that they need to be included even in the `-noexcept` build of +// libc++abi to support the case where some parts of a project are built +// with exception catching enabled, but at link time exception catching +// is disabled. In this case dependencies to these functions (and the JS +// functions which call them) will still exist in the final build. +extern "C" { + +int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, void **thrown) { + //std::type_info *t1 = static_cast<std::type_info*>(catchType); + //std::type_info *t2 = static_cast<std::type_info*>(excpType); + //printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown); + + void *temp = *thrown; + int ret = catchType->can_catch(excpType, temp); + if (ret) *thrown = temp; // apply changes only if we are catching + return ret; +} + +int __cxa_is_pointer_type(__shim_type_info* type) { + return !!dynamic_cast<__pointer_type_info*>(type); +} + +} +#endif // __USING_EMSCRIPTEN_EXCEPTIONS__ + } // __cxxabiv1 diff --git a/libcxxabi/src/stdlib_new_delete.cpp b/libcxxabi/src/stdlib_new_delete.cpp index 4a664e15a50f5..8035213da7e5f 100644 --- a/libcxxabi/src/stdlib_new_delete.cpp +++ b/libcxxabi/src/stdlib_new_delete.cpp @@ -37,8 +37,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC else #ifndef _LIBCXXABI_NO_EXCEPTIONS throw std::bad_alloc(); +#else +#ifdef __EMSCRIPTEN__ + // Abort here so that when exceptions are disabled, we do not just + // return 0 when malloc returns 0. + // We could also do this with set_new_handler, but that adds a + // global constructor and a table entry, overhead that we can avoid + // by doing it this way. + abort(); #else break; +#endif #endif } return p; _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits