29 changes: 28 additions & 1 deletion compiler-rt/lib/lsan/lsan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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();

Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/lsan/lsan_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/lsan/lsan_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
45 changes: 43 additions & 2 deletions compiler-rt/lib/lsan/lsan_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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));
}

Expand Down Expand Up @@ -181,6 +185,14 @@ static uptr GetCallerPC(const StackTrace &stack) {
// valid before reporting chunks as leaked.
bool LeakSuppressionContext::SuppressInvalid(const StackTrace &stack) {
uptr caller_pc = GetCallerPC(stack);
#if SANITIZER_EMSCRIPTEN
// caller_pr will always be 0 if we use malloc_context_size=0 (or 1) which
// we recommend under emscripten to save memory. It seems that this setting
// now (inadvertently?) suppreses all leaks.
// See https://reviews.llvm.org/D115319#3526676.
if (!caller_pc)
return false;
#endif
// If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark
// it as reachable, as we can't properly report its allocation stack anyway.
return !caller_pc ||
Expand Down Expand Up @@ -273,7 +285,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;
Expand All @@ -297,6 +318,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",
(void*)pp, (void*)cache_begin, (void*)cache_end);
continue;
}
#endif

m.set_tag(tag);
LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n",
(void *)pp, p, (void *)chunk,
Expand Down Expand Up @@ -362,6 +391,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) {
Expand Down Expand Up @@ -480,6 +510,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
// Add pointers reachable from ThreadContexts
ProcessThreadRegistry(frontier);
}
#endif // !SANITIZER_EMSCRIPTEN

# endif // SANITIZER_FUCHSIA

Expand All @@ -499,14 +530,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.
Expand Down Expand Up @@ -675,7 +714,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, &param->frontier);
ForEachChunk(CollectLeaksCb, &param->leaks);
// Clean up for subsequent leak checks. This assumes we did not overwrite any
Expand Down
6 changes: 5 additions & 1 deletion compiler-rt/lib/lsan/lsan_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/lsan/lsan_common_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
39 changes: 36 additions & 3 deletions compiler-rt/lib/lsan/lsan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
#include "lsan_common.h"
#include "lsan_thread.h"

#if SANITIZER_EMSCRIPTEN
#define __ATTRP_C11_THREAD ((void*)(uptr)-1)
#include <emscripten/heap.h>
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);
}
#endif

#include <stddef.h>

using namespace __lsan;
Expand Down Expand Up @@ -438,7 +449,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);
}

Expand All @@ -447,32 +462,47 @@ 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
// stored by pthread for future reuse even after thread destruction, and
// 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);
Expand All @@ -485,21 +515,22 @@ 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);
}

#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);
Expand Down Expand Up @@ -528,6 +559,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)) {
Expand All @@ -540,3 +572,4 @@ void InitializeInterceptors() {
}

} // namespace __lsan
#endif // SANITIZER_EMSCRIPTEN
4 changes: 2 additions & 2 deletions compiler-rt/lib/lsan/lsan_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {}

} // namespace __lsan

#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ void *BackgroundThread(void *arg) {
}
}

#if !SANITIZER_EMSCRIPTEN
void MaybeStartBackgroudThread() {
// Need to implement/test on other platforms.
// Start the background thread if one of the rss limits is given.
Expand Down Expand Up @@ -110,6 +111,7 @@ static struct BackgroudThreadStarted {
#else
void MaybeStartBackgroudThread() {}
#endif
#endif

void WriteToSyslog(const char *msg) {
InternalScopedString msg_copy;
Expand Down
11 changes: 7 additions & 4 deletions compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 differ on different platforms.
extern const int errno_EOWNERDEAD;
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ namespace __sanitizer {
typedef unsigned long long uptr;
typedef signed long long sptr;
#else
# if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC || SANITIZER_WINDOWS
# if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC || SANITIZER_WINDOWS || SANITIZER_EMSCRIPTEN
typedef unsigned long uptr;
typedef signed long sptr;
# else
Expand Down Expand Up @@ -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
Expand Down
118 changes: 104 additions & 14 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -59,7 +59,7 @@
#include <signal.h>
#include <sys/mman.h>
#include <sys/param.h>
#if !SANITIZER_SOLARIS
#if !SANITIZER_SOLARIS && !SANITIZER_EMSCRIPTEN
#include <sys/ptrace.h>
#endif
#include <sys/resource.h>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
}
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -523,6 +574,7 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
#endif
}
#endif
#endif

#if SANITIZER_GLIBC
u64 NanoTime() {
Expand All @@ -543,11 +595,21 @@ u64 NanoTime() {
}
#endif

#if SANITIZER_EMSCRIPTEN
extern "C" {
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++) {
Expand Down Expand Up @@ -616,6 +678,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
Expand Down Expand Up @@ -667,12 +730,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
Expand All @@ -683,6 +750,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
Expand Down Expand Up @@ -714,11 +783,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,
Expand Down Expand Up @@ -752,7 +823,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
Expand All @@ -761,12 +837,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));
Expand Down Expand Up @@ -861,6 +942,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;
Expand Down Expand Up @@ -910,7 +993,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];
Expand Down Expand Up @@ -1091,19 +1174,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
Expand Down Expand Up @@ -1765,7 +1852,7 @@ HandleSignalMode GetHandleSignalMode(int signum) {
return result;
}

#if !SANITIZER_GO
#if !SANITIZER_GO && !SANITIZER_EMSCRIPTEN
void *internal_start_thread(void *(*func)(void *arg), void *arg) {
if (&real_pthread_create == 0)
return nullptr;
Expand Down Expand Up @@ -2138,6 +2225,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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ u64 MonotonicNanoTime() {
}
#endif // SANITIZER_GLIBC && !SANITIZER_GO

#if !SANITIZER_EMSCRIPTEN
void ReExec() {
const char *pathname = "/proc/self/exe";

Expand Down Expand Up @@ -930,6 +931,7 @@ void ReExec() {
Printf("execve failed, errno %d\n", rverrno);
Die();
}
#endif

void UnmapFromTo(uptr from, uptr to) {
if (to == from)
Expand Down
15 changes: 13 additions & 2 deletions compiler-rt/lib/sanitizer_common/sanitizer_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
18 changes: 15 additions & 3 deletions compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 \
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"

Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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 {
Expand Down
30 changes: 30 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -139,11 +145,19 @@ void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) {
}

bool MprotectNoAccess(uptr addr, uptr size) {
#if SANITIZER_EMSCRIPTEN
return true;
#else
return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
#endif
}

bool MprotectReadOnly(uptr addr, uptr size) {
#if SANITIZER_EMSCRIPTEN
return true;
#else
return 0 == internal_mprotect((void *)addr, size, PROT_READ);
#endif
}

#if !SANITIZER_MAC
Expand Down Expand Up @@ -220,6 +234,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
Expand Down Expand Up @@ -254,6 +278,7 @@ void DumpProcessMap() {
UnmapOrDie(filename, kBufSize);
}
#endif
#endif

const char *GetPwd() {
return GetEnv("PWD");
Expand All @@ -274,6 +299,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());
Expand All @@ -285,6 +314,7 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
return true;
}
}
#endif
return false;
}

Expand Down
12 changes: 12 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -288,14 +295,17 @@ 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) {
// Some kinds of sandboxes may forbid filesystem access, so we won't be able
// 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,
Expand Down Expand Up @@ -419,6 +429,7 @@ void AdjustStackSize(void *attr_) {
}
#endif // !SANITIZER_GO

#if !SANITIZER_EMSCRIPTEN
pid_t StartSubprocess(const char *program, const char *const argv[],
const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
fd_t stderr_fd) {
Expand Down Expand Up @@ -493,6 +504,7 @@ int WaitForProcess(pid_t pid) {
}
return process_status;
}
#endif

bool IsStateDetached(int state) {
return state == PTHREAD_CREATE_DETACHED;
Expand Down
6 changes: 4 additions & 2 deletions compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
5 changes: 4 additions & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class SymbolizerTool {
~SymbolizerTool() {}
};

#if !SANITIZER_EMSCRIPTEN
// SymbolizerProcess encapsulates communication between the tool and
// external symbolizer program, running in a different subprocess.
// SymbolizerProcess may not be used from two threads simultaneously.
Expand Down Expand Up @@ -145,6 +146,7 @@ class LLVMSymbolizer final : public SymbolizerTool {
static const uptr kBufferSize = 16 * 1024;
char buffer_[kBufferSize];
};
#endif

// Parses one or more two-line strings in the following format:
// <function_name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
return module;
}

#if !SANITIZER_EMSCRIPTEN
// For now we assume the following protocol:
// For each request of the form
// <module_name> <module_offset>
Expand Down Expand Up @@ -551,6 +552,7 @@ bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) {
}
return true;
}
#endif

#endif // !SANITIZER_SYMBOLIZER_MARKUP

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -201,6 +201,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
return true;
}

#if !SANITIZER_EMSCRIPTEN
class Addr2LineProcess final : public SymbolizerProcess {
public:
Addr2LineProcess(const char *path, const char *module_name)
Expand Down Expand Up @@ -316,6 +317,7 @@ class Addr2LinePool final : public SymbolizerTool {
static const uptr dummy_address_ =
FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX);
};
#endif

# if SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
Expand Down
18 changes: 16 additions & 2 deletions compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 0 additions & 5 deletions compiler-rt/lib/ubsan/ubsan_checks.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/ubsan/ubsan_diag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
26 changes: 26 additions & 0 deletions compiler-rt/lib/ubsan/ubsan_flags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}

Expand All @@ -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();

Expand Down
23 changes: 2 additions & 21 deletions compiler-rt/lib/ubsan/ubsan_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/ubsan/ubsan_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 3 additions & 4 deletions compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Expand All @@ -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) {
Expand Down
8 changes: 5 additions & 3 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,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.
Expand Down Expand Up @@ -388,7 +389,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
Expand Down Expand Up @@ -1146,7 +1147,8 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container(
defined(__APPLE__) || \
defined(__sun__) || \
defined(__MVS__) || \
defined(_AIX)
defined(_AIX) || \
defined(__EMSCRIPTEN__)
# define _LIBCPP_HAS_THREAD_API_PTHREAD
# elif defined(__Fuchsia__)
// TODO(44575): Switch to C11 thread API when possible.
Expand Down
3 changes: 1 addition & 2 deletions libcxx/include/__locale
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@
# include <__support/newlib/xlocale.h>
#elif defined(__OpenBSD__)
# include <__support/openbsd/xlocale.h>
#elif (defined(__APPLE__) || defined(__FreeBSD__) \
|| defined(__EMSCRIPTEN__) || defined(__IBMCPP__))
#elif (defined(__APPLE__) || defined(__FreeBSD__) || defined(__IBMCPP__))
# include <xlocale.h>
#elif defined(__Fuchsia__)
# include <__support/fuchsia/xlocale.h>
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/locale
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/typeinfo
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
2 changes: 2 additions & 0 deletions libcxx/src/include/config_elast.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
// No _LIBCPP_ELAST needed on Fuchsia
#elif defined(__wasi__)
// No _LIBCPP_ELAST needed on WASI
#elif defined(__EMSCRIPTEN__)
// No _LIBCPP_ELAST needed on Emscripten
#elif defined(__linux__) || defined(_LIBCPP_HAS_MUSL_LIBC)
#define _LIBCPP_ELAST 4095
#elif defined(__APPLE__)
Expand Down
9 changes: 9 additions & 0 deletions libcxx/src/new.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions libcxx/src/support/runtime/exception_fallback.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -80,6 +83,7 @@ int uncaught_exceptions() noexcept
fprintf(stderr, "uncaught_exceptions not yet implemented\n");
::abort();
}
#endif // !__EMSCRIPTEN__


exception::~exception() noexcept
Expand Down
22 changes: 13 additions & 9 deletions libcxxabi/include/cxxabi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
9 changes: 9 additions & 0 deletions libcxxabi/src/abort_message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
25 changes: 15 additions & 10 deletions libcxxabi/src/cxa_exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 =
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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]);
Expand All @@ -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 =
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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();
Expand Down
26 changes: 26 additions & 0 deletions libcxxabi/src/cxa_exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -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++
Expand All @@ -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;

Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion libcxxabi/src/cxa_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
52 changes: 32 additions & 20 deletions libcxxabi/src/cxa_personality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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 |
Expand All @@ -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 |
Expand All @@ -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 |
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -678,33 +680,33 @@ 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);
uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
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
results.reason = _URC_CONTINUE_UNWIND;
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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -832,15 +832,15 @@ 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
// Something bad has happened. We should never get here.
// 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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
7 changes: 6 additions & 1 deletion libcxxabi/src/cxa_thread_atexit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
31 changes: 31 additions & 0 deletions libcxxabi/src/private_typeinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions libcxxabi/src/stdlib_new_delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down