Skip to content
7 changes: 6 additions & 1 deletion clang/lib/Driver/ToolChains/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,13 @@ void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
SanitizerMask WebAssembly::getSupportedSanitizers() const {
SanitizerMask Res = ToolChain::getSupportedSanitizers();
if (getTriple().isOSEmscripten()) {
Res |= SanitizerKind::Vptr | SanitizerKind::Leak | SanitizerKind::Address;
Res |= SanitizerKind::Vptr | SanitizerKind::Leak;
}

if (getTriple().isOSEmscripten() || getTriple().isOSWASI()) {
Res |= SanitizerKind::Address;
}

// -fsanitize=function places two words before the function label, which are
// -unsupported.
Res &= ~SanitizerKind::Function;
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ else()
set(SANITIZER_LIMIT_FRAME_SIZE FALSE)
endif()

if(FUCHSIA OR UNIX)
if((FUCHSIA OR UNIX) AND NOT CMAKE_SYSTEM_NAME STREQUAL "WASI")
set(SANITIZER_USE_SYMBOLS TRUE)
else()
set(SANITIZER_USE_SYMBOLS FALSE)
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ endif()

set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64} ${RISCV64}
${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9}
${HEXAGON} ${LOONGARCH64})
${HEXAGON} ${LOONGARCH64} ${WASM32})
set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
${LOONGARCH64})
${LOONGARCH64} ${WASM32})
set(ALL_ASAN_ABI_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM64_32})
set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64})
set(ALL_RTSAN_SUPPORTED_ARCH ${X86_64} ${ARM64})
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")

if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
(OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|Fuchsia|SunOS" OR
(OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|Fuchsia|SunOS|WASI" OR
(OS_NAME MATCHES "Windows" AND NOT CYGWIN AND
(NOT MINGW OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"))))
set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)
Expand Down
52 changes: 32 additions & 20 deletions compiler-rt/lib/asan/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Build for the AddressSanitizer runtime support library.

set(COMPILER_RT_ASAN_BUILD_SHARED_LIBS_default ON)
if (CMAKE_SYSTEM_NAME STREQUAL "WASI")
set(COMPILER_RT_ASAN_BUILD_SHARED_LIBS_default OFF)
endif()
option(COMPILER_RT_ASAN_BUILD_SHARED_LIBS
"Build AddressSanitizer shared libraries" ${COMPILER_RT_ASAN_BUILD_SHARED_LIBS_default})

set(ASAN_SOURCES
asan_allocator.cpp
asan_activation.cpp
Expand Down Expand Up @@ -29,10 +36,13 @@ set(ASAN_SOURCES
asan_stats.cpp
asan_suppressions.cpp
asan_thread.cpp
asan_wasi.cpp
asan_win.cpp
wasi/memset.c
wasi/memcpy.c
)

if (NOT WIN32 AND NOT APPLE)
if (NOT WIN32 AND NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "WASI")
list(APPEND ASAN_SOURCES
asan_interceptors_vfork.S
)
Expand Down Expand Up @@ -293,25 +303,27 @@ else()
SanitizerCommonWeakInterception)
endif()

add_compiler_rt_runtime(clang_rt.asan
SHARED
ARCHS ${arch}
OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
RTAsan_dynamic
# The only purpose of RTAsan_dynamic_version_script_dummy is to
# carry a dependency of the shared runtime on the version script.
# Replacing it with a straightforward
# add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list)
# generates an order-only dependency in ninja.
RTAsan_dynamic_version_script_dummy
RTUbsan_cxx
${ASAN_DYNAMIC_WEAK_INTERCEPTION}
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
LINK_FLAGS ${ASAN_DYNAMIC_LINK_FLAGS}
${VERSION_SCRIPT_FLAG}
LINK_LIBS ${ASAN_DYNAMIC_LIBS}
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
PARENT_TARGET asan)
if (COMPILER_RT_ASAN_BUILD_SHARED_LIBS)
add_compiler_rt_runtime(clang_rt.asan
SHARED
ARCHS ${arch}
OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
RTAsan_dynamic
# The only purpose of RTAsan_dynamic_version_script_dummy is to
# carry a dependency of the shared runtime on the version script.
# Replacing it with a straightforward
# add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list)
# generates an order-only dependency in ninja.
RTAsan_dynamic_version_script_dummy
RTUbsan_cxx
${ASAN_DYNAMIC_WEAK_INTERCEPTION}
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
LINK_FLAGS ${ASAN_DYNAMIC_LINK_FLAGS}
${VERSION_SCRIPT_FLAG}
LINK_LIBS ${ASAN_DYNAMIC_LIBS}
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
PARENT_TARGET asan)
endif()

if (SANITIZER_USE_SYMBOLS AND NOT ${arch} STREQUAL "i386")
add_sanitizer_rt_symbols(clang_rt.asan_cxx
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/asan/asan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_libc.h"

// There is no general interception at all on Fuchsia.
// There is no general interception at all on Fuchsia and WASI.
// Only the functions in asan_interceptors_memintrinsics.cpp are
// really defined to replace libc functions.
#if !SANITIZER_FUCHSIA
#if !SANITIZER_FUCHSIA && !SANITIZER_WASI

# if SANITIZER_POSIX
# include "sanitizer_common/sanitizer_posix.h"
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/asan_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void InitializePlatformInterceptors();

// Use macro to describe if specific function should be
// intercepted on a given platform.
#if !SANITIZER_WINDOWS
#if !SANITIZER_WINDOWS && !SANITIZER_WASI
# define ASAN_INTERCEPT__LONGJMP 1
# define ASAN_INTERCEPT_INDEX 1
# define ASAN_INTERCEPT_PTHREAD_CREATE 1
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,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_WASI

// Fuchsia doesn't use sanitizer_common_interceptors.inc, but
// the only things there it wants are these three. Just define them
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/asan_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
// If set, values like allocator chunk size, as well as defaults for some flags
// will be changed towards less memory overhead.
#ifndef ASAN_LOW_MEMORY
# if SANITIZER_IOS || SANITIZER_ANDROID
# if SANITIZER_IOS || SANITIZER_ANDROID || SANITIZER_WASI
# define ASAN_LOW_MEMORY 1
# else
# define ASAN_LOW_MEMORY 0
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/asan_malloc_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_WASI

# include "asan_allocator.h"
# include "asan_interceptors.h"
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/asan/asan_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init.

# if defined(__sparc__) && SANITIZER_WORDSIZE == 64
# include "asan_mapping_sparc64.h"
# elif SANITIZER_WASI
# include "asan_mapping_wasi.h"
# else
# define MEM_TO_SHADOW(mem) \
(((mem) >> ASAN_SHADOW_SCALE) + (ASAN_SHADOW_OFFSET))
Expand Down
86 changes: 86 additions & 0 deletions compiler-rt/lib/asan/asan_mapping_wasi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//===-- asan_mapping_wasi.h ----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// WASI-specific definitions for ASan memory mapping.
//===----------------------------------------------------------------------===//

#ifndef ASAN_MAPPING_WASI_H
#define ASAN_MAPPING_WASI_H

extern char __global_base;

#define kLowMemBeg ((uptr) &__global_base)
#define kLowMemEnd ((kLowShadowBeg << ASAN_SHADOW_SCALE) - 1)

#define kLowShadowBeg 0
#define kLowShadowEnd ((uptr) &__global_base - 1)

#define kHighMemBeg 0

#define kHighShadowBeg 0
#define kHighShadowEnd 0

#define kMidShadowBeg 0
#define kMidShadowEnd 0

#define kShadowGapBeg (kLowMemEnd + 1)
#define kShadowGapEnd 0xFFFFFFFF

#define kShadowGap2Beg 0
#define kShadowGap2End 0

#define kShadowGap3Beg 0
#define kShadowGap3End 0

// The first 1/8 of the shadow memory space is shadowing itself.
// This allows attempted accesses into the shadow memory, as well as null
// pointer dereferences, to be detected properly.
// The shadow memory of the shadow memory is poisoned.
#define MEM_TO_SHADOW(mem) ((mem) >> ASAN_SHADOW_SCALE)
#define SHADOW_TO_MEM(mem) ((mem) << ASAN_SHADOW_SCALE)

namespace __asan {

static inline bool AddrIsInLowMem(uptr a) {
PROFILE_ASAN_MAPPING();
return a >= kLowMemBeg && a <= kLowMemEnd;
}

static inline bool AddrIsInLowShadow(uptr a) {
PROFILE_ASAN_MAPPING();
return a >= kLowShadowBeg && a <= kLowShadowEnd;
}

static inline bool AddrIsInMidMem(uptr a) {
PROFILE_ASAN_MAPPING();
return false;
}

static inline bool AddrIsInMidShadow(uptr a) {
PROFILE_ASAN_MAPPING();
return false;
}

static inline bool AddrIsInHighMem(uptr a) {
PROFILE_ASAN_MAPPING();
return false;
}

static inline bool AddrIsInHighShadow(uptr a) {
PROFILE_ASAN_MAPPING();
return false;
}

static inline bool AddrIsInShadowGap(uptr a) {
PROFILE_ASAN_MAPPING();
return a >= kShadowGapBeg;
}

} // namespace __asan

#endif // ASAN_MAPPING_WASI_H
1 change: 1 addition & 0 deletions compiler-rt/lib/asan/asan_poisoning.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ 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 ||
SANITIZER_WASI == 1 ||
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
} else {
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/asan_shadow_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "sanitizer_common/sanitizer_platform.h"

// asan_fuchsia.cpp has their own InitializeShadowMemory implementation.
#if !SANITIZER_FUCHSIA
#if !SANITIZER_FUCHSIA && !SANITIZER_WASI

# include "asan_internal.h"
# include "asan_mapping.h"
Expand Down
80 changes: 80 additions & 0 deletions compiler-rt/lib/asan/asan_wasi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//===-- asan_wasi.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// WASI-specific details.
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#include "sanitizer_common/sanitizer_internal_defs.h"

#if SANITIZER_WASI

#include "asan/asan_poisoning.h"
#include "asan_interceptors.h"
#include "asan_internal.h"

namespace __asan {

void InitializeShadowMemory() {
// Poison the shadow memory itself to catch invalid shadow accesses and
// also to catch null pointer dereferences.
FastPoisonShadow(kLowShadowBeg, kLowShadowEnd - kLowShadowBeg, kAsanGlobalRedzoneMagic);
}

void InitializePlatformInterceptors() {}
void InitializePlatformExceptionHandlers() {}

void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
void InitializeAsanInterceptors() {}

void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
UNIMPLEMENTED();
}

bool PlatformUnpoisonStacks() { return false; }

// Simple thread local storage implementation for WASI
static thread_local void *per_thread;

void *AsanTSDGet() { return per_thread; }

void AsanTSDSet(void *tsd) { per_thread = tsd; }

void AsanTSDInit(void (*destructor)(void *tsd)) {
DCHECK(destructor == &PlatformTSDDtor);
}

void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }

void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
UNIMPLEMENTED();
}

void InstallAtForkHandler() {
// WASI doesn't support fork
}

void FlushUnneededASanShadowMemory(uptr p, uptr size) {
// No-op as madvise is not supported on WASI
}

// On WASI, leak detection is not supported yet
void InstallAtExitCheckLeaks() {}

// On WASI Preview 1, dlopen is not supported
bool HandleDlopenInit() { return false; }

// WASI does not support ASLR
void TryReExecWithoutASLR() {}

} // namespace __asan

#endif // SANITIZER_WASI
14 changes: 14 additions & 0 deletions compiler-rt/lib/asan/wasi/memcpy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#if __wasi__
#include <string.h>
#include <stdint.h>
#include <endian.h>

void *__wasilibc_memcpy(void *restrict dest, const void *restrict src, size_t n)
{
unsigned char *d = dest;
const unsigned char *s = src;

for (; n; n--) *d++ = *s++;
return dest;
}
#endif
Loading