Skip to content

Commit b52556f

Browse files
authored
Add missing compiler-rt files from emscripten (#6)
1 parent 53de398 commit b52556f

12 files changed

+972
-0
lines changed

compiler-rt/__trap.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void __trap() {
2+
__builtin_trap();
3+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2018 The Emscripten Authors. All rights reserved.
3+
* Emscripten is available under two separate licenses, the MIT license and the
4+
* University of Illinois/NCSA Open Source License. Both these licenses can be
5+
* found in the LICENSE file.
6+
*
7+
* Support functions for emscripten setjmp/longjmp and exception handling
8+
* support. References to the things below are generated in the LLVM backend.
9+
* See: https://llvm.org/doxygen/WebAssemblyLowerEmscriptenEHSjLj_8cpp.html
10+
*/
11+
12+
#include <stdint.h>
13+
#include <threads.h>
14+
15+
thread_local uintptr_t __THREW__ = 0;
16+
thread_local int __threwValue = 0;
17+
18+
void setThrew(uintptr_t threw, int value) {
19+
if (__THREW__ == 0) {
20+
__THREW__ = threw;
21+
__threwValue = value;
22+
}
23+
}

compiler-rt/emscripten_setjmp.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2020 The Emscripten Authors. All rights reserved.
3+
* Emscripten is available under two separate licenses, the MIT license and the
4+
* University of Illinois/NCSA Open Source License. Both these licenses can be
5+
* found in the LICENSE file.
6+
*/
7+
8+
#include <stdint.h>
9+
#include <stdlib.h>
10+
#include <setjmp.h>
11+
#include <threads.h>
12+
13+
// 0 - Nothing thrown
14+
// 1 - Exception thrown
15+
// Other values - jmpbuf pointer in the case that longjmp was thrown
16+
static uintptr_t setjmpId = 0;
17+
18+
typedef struct TableEntry {
19+
uintptr_t id;
20+
uint32_t label;
21+
} TableEntry;
22+
23+
extern void setTempRet0(uint32_t value);
24+
extern void setThrew(uintptr_t threw, int value);
25+
26+
TableEntry* saveSetjmp(uintptr_t* env, uint32_t label, TableEntry* table, uint32_t size) {
27+
// Not particularly fast: slow table lookup of setjmpId to label. But setjmp
28+
// prevents relooping anyhow, so slowness is to be expected. And typical case
29+
// is 1 setjmp per invocation, or less.
30+
uint32_t i = 0;
31+
setjmpId++;
32+
*env = setjmpId;
33+
while (i < size) {
34+
if (table[i].id == 0) {
35+
table[i].id = setjmpId;
36+
table[i].label = label;
37+
// prepare next slot
38+
table[i + 1].id = 0;
39+
setTempRet0(size);
40+
return table;
41+
}
42+
i++;
43+
}
44+
// grow the table
45+
size *= 2;
46+
table = (TableEntry*)realloc(table, sizeof(TableEntry) * (size +1));
47+
table = saveSetjmp(env, label, table, size);
48+
setTempRet0(size); // FIXME: unneeded?
49+
return table;
50+
}
51+
52+
uint32_t testSetjmp(uintptr_t id, TableEntry* table, uint32_t size) {
53+
uint32_t i = 0;
54+
while (i < size) {
55+
uintptr_t curr = table[i].id;
56+
if (curr == 0) break;
57+
if (curr == id) {
58+
return table[i].label;
59+
}
60+
i++;
61+
}
62+
return 0;
63+
}
64+
65+
#if !defined(__USING_WASM_SJLJ__)
66+
67+
#include "emscripten_internal.h"
68+
69+
void emscripten_longjmp(uintptr_t env, int val) {
70+
setThrew(env, val);
71+
_emscripten_throw_longjmp();
72+
}
73+
#endif
74+
75+
#ifdef __USING_WASM_SJLJ__
76+
77+
struct __WasmLongjmpArgs {
78+
void *env;
79+
int val;
80+
};
81+
82+
thread_local struct __WasmLongjmpArgs __wasm_longjmp_args;
83+
84+
// Wasm EH allows us to throw and catch multiple values, but that requires
85+
// multivalue support in the toolchain, whch is not reliable at the time.
86+
// TODO Consider switching to throwing two values at the same time later.
87+
void __wasm_longjmp(void *env, int val) {
88+
__wasm_longjmp_args.env = env;
89+
__wasm_longjmp_args.val = val;
90+
__builtin_wasm_throw(1, &__wasm_longjmp_args);
91+
}
92+
93+
#endif

compiler-rt/emscripten_tempret.s

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.globaltype tempRet0, i32
2+
tempRet0:
3+
4+
.globl setTempRet0
5+
setTempRet0:
6+
.functype setTempRet0 (i32) -> ()
7+
local.get 0
8+
global.set tempRet0
9+
end_function
10+
11+
.globl getTempRet0
12+
getTempRet0:
13+
.functype getTempRet0 () -> (i32)
14+
global.get tempRet0
15+
end_function
16+
17+
# These aliases exist solely for LegalizeJSInterface pass in binaryen
18+
# They get exported by emcc and the exports are then removed by the
19+
# binaryen pass
20+
.globl __get_temp_ret
21+
.type __get_temp_ret, @function
22+
__get_temp_ret = getTempRet0
23+
24+
.globl __set_temp_ret
25+
.type __set_temp_ret, @function
26+
__set_temp_ret = setTempRet0
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#include "asan_interceptors.h"
2+
#include "asan_internal.h"
3+
#include "asan_mapping.h"
4+
#include "asan_poisoning.h"
5+
#include "asan_stack.h"
6+
#include "asan_thread.h"
7+
#include "lsan/lsan_common.h" // for CAN_SANITIZE_LEAKS
8+
9+
#if SANITIZER_EMSCRIPTEN
10+
#include <emscripten.h>
11+
#include <emscripten/heap.h>
12+
#include <cassert>
13+
#include <cstddef>
14+
#include <pthread.h>
15+
#define __ATTRP_C11_THREAD ((void*)(uptr)-1)
16+
17+
namespace __asan {
18+
19+
void InitializeShadowMemory() {
20+
// Poison the shadow memory of the shadow area at the start of the address
21+
// space. This helps catching null pointer dereference.
22+
FastPoisonShadow(kLowShadowBeg, kLowShadowEnd - kLowShadowBeg, 0xff);
23+
24+
// Assert that the shadow region is large enough. We don't want to start
25+
// running into the static data region which starts right after the shadow
26+
// region.
27+
uptr max_address =
28+
(__builtin_wasm_memory_size(0) * uint64_t(WASM_PAGE_SIZE)) - 1;
29+
uptr max_shadow_address = MEM_TO_SHADOW(max_address);
30+
// TODO(sbc): In the growable memory case we should really be checking this
31+
// every time we grow.
32+
assert(max_shadow_address <= kLowShadowEnd && "shadow region is too small");
33+
}
34+
35+
void AsanCheckDynamicRTPrereqs() {}
36+
void AsanCheckIncompatibleRT() {}
37+
void InitializePlatformInterceptors() {}
38+
void InitializePlatformExceptionHandlers() {}
39+
bool IsSystemHeapAddress (uptr addr) { return false; }
40+
41+
void *AsanDoesNotSupportStaticLinkage() {
42+
// On Linux, this is some magic that fails linking with -static.
43+
// On Emscripten, we have to do static linking, so we stub this out.
44+
return nullptr;
45+
}
46+
47+
void InitializeAsanInterceptors() {}
48+
49+
void FlushUnneededASanShadowMemory(uptr p, uptr size) {}
50+
51+
extern "C" {
52+
int emscripten_builtin_pthread_create(pthread_t *thread,
53+
const pthread_attr_t *attr,
54+
void *(*callback)(void *), void *arg);
55+
}
56+
57+
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
58+
AsanThread *t = (AsanThread *)arg;
59+
SetCurrentThread(t);
60+
return t->ThreadStart(GetTid());
61+
}
62+
63+
INTERCEPTOR(int, pthread_create, pthread_t *thread,
64+
const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg) {
65+
EnsureMainThreadIDIsCorrect();
66+
// Strict init-order checking is thread-hostile.
67+
if (flags()->strict_init_order)
68+
StopInitOrderChecking();
69+
GET_STACK_TRACE_THREAD;
70+
int detached = 0;
71+
if (attr && attr != __ATTRP_C11_THREAD)
72+
pthread_attr_getdetachstate(attr, &detached);
73+
74+
u32 current_tid = GetCurrentTidOrInvalid();
75+
AsanThread *t =
76+
AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
77+
78+
int result;
79+
{
80+
// Ignore all allocations made by pthread_create: thread stack/TLS may be
81+
// stored by pthread for future reuse even after thread destruction, and
82+
// the linked list it's stored in doesn't even hold valid pointers to the
83+
// objects, the latter are calculated by obscure pointer arithmetic.
84+
#if CAN_SANITIZE_LEAKS
85+
__lsan::ScopedInterceptorDisabler disabler;
86+
#endif
87+
result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
88+
}
89+
if (result != 0) {
90+
// If the thread didn't start delete the AsanThread to avoid leaking it.
91+
// Note AsanThreadContexts never get destroyed so the AsanThreadContext
92+
// that was just created for the AsanThread is wasted.
93+
t->Destroy();
94+
}
95+
return result;
96+
}
97+
98+
} // namespace __asan
99+
100+
namespace __lsan {
101+
102+
#ifndef __EMSCRIPTEN_PTHREADS__
103+
// XXX HACK: Emscripten treats thread_local variables the same as globals in
104+
// non-threaded builds, so a hack was introduced where we skip the allocator
105+
// cache in the common module. Now we have to define this symbol to keep that
106+
// hack working when using LSan as part of ASan without threads.
107+
void GetAllocatorCacheRange(uptr *begin, uptr *end) {
108+
*begin = *end = 0;
109+
}
110+
#endif
111+
112+
u32 GetCurrentThread() { return __asan::GetCurrentThread()->tid(); }
113+
114+
} // namespace __lsan
115+
116+
#endif // SANITIZER_EMSCRIPTEN
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//===-- asan_mapping_emscripten.h -------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of AddressSanitizer, an address sanity checker.
11+
//
12+
// Emscripten-specific definitions for ASan memory mapping.
13+
//===----------------------------------------------------------------------===//
14+
#ifndef ASAN_MAPPING_EMSCRIPTEN_H
15+
#define ASAN_MAPPING_EMSCRIPTEN_H
16+
17+
extern char __global_base;
18+
19+
#define kLowMemBeg ((uptr) &__global_base)
20+
#define kLowMemEnd ((kLowShadowBeg << ASAN_SHADOW_SCALE) - 1)
21+
22+
#define kLowShadowBeg 0
23+
#define kLowShadowEnd ((uptr) &__global_base - 1)
24+
25+
#define kHighMemBeg 0
26+
27+
#define kHighShadowBeg 0
28+
#define kHighShadowEnd 0
29+
30+
#define kMidShadowBeg 0
31+
#define kMidShadowEnd 0
32+
33+
#define kShadowGapBeg (kLowMemEnd + 1)
34+
#define kShadowGapEnd 0xFFFFFFFF
35+
36+
#define kShadowGap2Beg 0
37+
#define kShadowGap2End 0
38+
39+
#define kShadowGap3Beg 0
40+
#define kShadowGap3End 0
41+
42+
// The first 1/8 of the shadow memory space is shadowing itself.
43+
// This allows attempted accesses into the shadow memory, as well as null
44+
// pointer dereferences, to be detected properly.
45+
// The shadow memory of the shadow memory is poisoned.
46+
#define MEM_TO_SHADOW(mem) ((mem) >> ASAN_SHADOW_SCALE)
47+
#define SHADOW_TO_MEM(mem) ((mem) << ASAN_SHADOW_SCALE)
48+
49+
namespace __asan {
50+
51+
static inline bool AddrIsInLowMem(uptr a) {
52+
PROFILE_ASAN_MAPPING();
53+
return a >= kLowMemBeg && a <= kLowMemEnd;
54+
}
55+
56+
static inline bool AddrIsInLowShadow(uptr a) {
57+
PROFILE_ASAN_MAPPING();
58+
return a >= kLowShadowBeg && a <= kLowShadowEnd;
59+
}
60+
61+
static inline bool AddrIsInMidMem(uptr a) {
62+
PROFILE_ASAN_MAPPING();
63+
return false;
64+
}
65+
66+
static inline bool AddrIsInMidShadow(uptr a) {
67+
PROFILE_ASAN_MAPPING();
68+
return false;
69+
}
70+
71+
static inline bool AddrIsInHighMem(uptr a) {
72+
PROFILE_ASAN_MAPPING();
73+
return false;
74+
}
75+
76+
static inline bool AddrIsInHighShadow(uptr a) {
77+
PROFILE_ASAN_MAPPING();
78+
return false;
79+
}
80+
81+
static inline bool AddrIsInShadowGap(uptr a) {
82+
PROFILE_ASAN_MAPPING();
83+
return a >= kShadowGapBeg;
84+
}
85+
86+
} // namespace __asan
87+
88+
#endif // ASAN_MAPPING_EMSCRIPTEN_H

0 commit comments

Comments
 (0)