forked from emscripten-core/emscripten
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow emscripten to use the minimal ubsan runtime (emscripten-core#8617)
This works with the wasm backend, whether generating wasm or asm.js. Also added `emscripten_return_address` which implements the functionality of `__builtin_return_address` when running both wasm and asm.js.
- Loading branch information
1 parent
79a1955
commit 82292b5
Showing
17 changed files
with
478 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -403,3 +403,4 @@ a license to everyone to use it as detailed in LICENSE.) | |
* Simon Cooper <[email protected]> | ||
* Amir Rasouli <[email protected]> | ||
* Nico Weber <[email protected]> | ||
* Guanzhong Chen <[email protected]> (copyright owned by Google, Inc.) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
These files are from compiler-rt. | ||
|
||
Last Changed Rev: 351636 | ||
Last Changed Date: 2019-01-19 | ||
|
||
=========================================================================== | ||
|
||
* `ubsan_minimal_handlers.cpp` -- changed to use | ||
`emscripten_return_address` as `__builtin_return_address` is not yet | ||
available in clang target `wasm-unknown-emscripten`. | ||
* `sanitizer_atomic.h` -- based on `sanitizer_atomic.h`, | ||
`sanitizer_atomic_clang.h` and `sanitizer_atomic_clang_other.h` in | ||
upstream, combined into one to avoid pulling in and porting the entire | ||
`sanitizer_common` directory from upstream. |
155 changes: 155 additions & 0 deletions
155
system/lib/compiler-rt/lib/ubsan_minimal/sanitizer_atomic.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
/** | ||
* This file is based on sanitizer_atomic.h, sanitizer_atomic_clang.h, and | ||
* sanitizer_atomic_clang_other.h from compiler-rt. | ||
* Last changed revision: 351636. | ||
* Last changed date: 2019-01-19. | ||
* | ||
* The files are combined into one to avoid depending on many unneeded headers | ||
* in compiler-rt/lib/sanitizer_common. | ||
*/ | ||
|
||
//===-- sanitizer_atomic.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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef SANITIZER_ATOMIC_H | ||
#define SANITIZER_ATOMIC_H | ||
|
||
#include <cinttypes> | ||
|
||
#ifndef INLINE | ||
#define INLINE inline | ||
#endif | ||
#define ALIGNED(x) __attribute__((aligned(x))) | ||
#define DCHECK(a) | ||
|
||
namespace __sanitizer { | ||
|
||
enum memory_order { | ||
memory_order_relaxed = 1 << 0, | ||
memory_order_seq_cst = 1 << 5 | ||
}; | ||
|
||
struct atomic_uint8_t { | ||
typedef std::uint8_t Type; | ||
volatile Type val_dont_use; | ||
}; | ||
|
||
struct atomic_uint16_t { | ||
typedef std::uint16_t Type; | ||
volatile Type val_dont_use; | ||
}; | ||
|
||
struct atomic_sint32_t { | ||
typedef std::int32_t Type; | ||
volatile Type val_dont_use; | ||
}; | ||
|
||
struct atomic_uint32_t { | ||
typedef std::uint32_t Type; | ||
volatile Type val_dont_use; | ||
}; | ||
|
||
struct atomic_uint64_t { | ||
typedef std::uint64_t Type; | ||
// On 32-bit platforms u64 is not necessary aligned on 8 bytes. | ||
volatile ALIGNED(8) Type val_dont_use; | ||
}; | ||
|
||
struct atomic_uintptr_t { | ||
typedef std::uintptr_t Type; | ||
volatile Type val_dont_use; | ||
}; | ||
|
||
typedef std::uintptr_t uptr; | ||
|
||
template<typename T> | ||
INLINE typename T::Type atomic_load( | ||
const volatile T *a, memory_order mo) { | ||
DCHECK(mo & memory_order_relaxed); | ||
DCHECK(!((uptr)a % sizeof(*a))); | ||
typename T::Type v; | ||
|
||
if (sizeof(*a) < 8 || sizeof(void*) == 8) { | ||
// Assume that aligned loads are atomic. | ||
v = a->val_dont_use; | ||
} else { | ||
// 64-bit load on 32-bit platform. | ||
// Gross, but simple and reliable. | ||
// Assume that it is not in read-only memory. | ||
v = __sync_fetch_and_add( | ||
const_cast<typename T::Type volatile *>(&a->val_dont_use), 0); | ||
} | ||
return v; | ||
} | ||
|
||
template<typename T> | ||
INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { | ||
DCHECK(mo & memory_order_relaxed); | ||
DCHECK(!((uptr)a % sizeof(*a))); | ||
|
||
if (sizeof(*a) < 8 || sizeof(void*) == 8) { | ||
// Assume that aligned loads are atomic. | ||
a->val_dont_use = v; | ||
} else { | ||
// 64-bit store on 32-bit platform. | ||
// Gross, but simple and reliable. | ||
typename T::Type cmp = a->val_dont_use; | ||
typename T::Type cur; | ||
for (;;) { | ||
cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v); | ||
if (cur == cmp || cur == v) | ||
break; | ||
cmp = cur; | ||
} | ||
} | ||
} | ||
|
||
// We would like to just use compiler builtin atomic operations | ||
// for loads and stores, but they are mostly broken in clang: | ||
// - they lead to vastly inefficient code generation | ||
// (http://llvm.org/bugs/show_bug.cgi?id=17281) | ||
// - 64-bit atomic operations are not implemented on x86_32 | ||
// (http://llvm.org/bugs/show_bug.cgi?id=15034) | ||
// - they are not implemented on ARM | ||
// error: undefined reference to '__atomic_load_4' | ||
|
||
// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html | ||
// for mappings of the memory model to different processors. | ||
|
||
template <typename T> | ||
INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, | ||
typename T::Type xchg, | ||
memory_order mo) { | ||
typedef typename T::Type Type; | ||
Type cmpv = *cmp; | ||
Type prev; | ||
prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); | ||
if (prev == cmpv) return true; | ||
*cmp = prev; | ||
return false; | ||
} | ||
|
||
// Clutter-reducing helpers. | ||
|
||
template<typename T> | ||
INLINE typename T::Type atomic_load_relaxed(const volatile T *a) { | ||
return atomic_load(a, memory_order_relaxed); | ||
} | ||
|
||
template<typename T> | ||
INLINE void atomic_store_relaxed(volatile T *a, typename T::Type v) { | ||
atomic_store(a, v, memory_order_relaxed); | ||
} | ||
|
||
} // namespace __sanitizer | ||
|
||
#endif // SANITIZER_ATOMIC_H |
130 changes: 130 additions & 0 deletions
130
system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/** | ||
* Copied from compiler-rt. | ||
* Last changed revision: 351178 | ||
* Last changed date: 2019-01-15. | ||
* | ||
* Changes: | ||
* * switched to using emscripten_return_address instead of | ||
__builtin_return_address. clang currently rejects the latter on wasm. | ||
*/ | ||
#include "sanitizer_atomic.h" | ||
|
||
#include <stdlib.h> | ||
#include <stdint.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
#ifdef KERNEL_USE | ||
extern "C" void ubsan_message(const char *msg); | ||
static void message(const char *msg) { ubsan_message(msg); } | ||
#else | ||
static void message(const char *msg) { | ||
write(2, msg, strlen(msg)); | ||
} | ||
#endif | ||
|
||
static const int kMaxCallerPcs = 20; | ||
static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs]; | ||
// Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means | ||
// that "too many errors" has already been reported. | ||
static __sanitizer::atomic_uint32_t caller_pcs_sz; | ||
|
||
__attribute__((noinline)) static bool report_this_error(void *caller_p) { | ||
uintptr_t caller = reinterpret_cast<uintptr_t>(caller_p); | ||
if (caller == 0) return false; | ||
while (true) { | ||
unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz); | ||
if (sz > kMaxCallerPcs) return false; // early exit | ||
// when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg | ||
// succeeds in order to not print it multiple times. | ||
if (sz > 0 && sz < kMaxCallerPcs) { | ||
uintptr_t p; | ||
for (unsigned i = 0; i < sz; ++i) { | ||
p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]); | ||
if (p == 0) break; // Concurrent update. | ||
if (p == caller) return false; | ||
} | ||
if (p == 0) continue; // FIXME: yield? | ||
} | ||
|
||
if (!__sanitizer::atomic_compare_exchange_strong( | ||
&caller_pcs_sz, &sz, sz + 1, __sanitizer::memory_order_seq_cst)) | ||
continue; // Concurrent update! Try again from the start. | ||
|
||
if (sz == kMaxCallerPcs) { | ||
message("ubsan: too many errors\n"); | ||
return false; | ||
} | ||
__sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller); | ||
return true; | ||
} | ||
} | ||
|
||
#if defined(__ANDROID__) | ||
extern "C" __attribute__((weak)) void android_set_abort_message(const char *); | ||
static void abort_with_message(const char *msg) { | ||
if (&android_set_abort_message) android_set_abort_message(msg); | ||
abort(); | ||
} | ||
#else | ||
static void abort_with_message(const char *) { abort(); } | ||
#endif | ||
|
||
#if SANITIZER_DEBUG | ||
namespace __sanitizer { | ||
// The DCHECK macro needs this symbol to be defined. | ||
void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { | ||
message("Sanitizer CHECK failed: "); | ||
message(file); | ||
message(":?? : "); // FIXME: Show line number. | ||
message(cond); | ||
abort(); | ||
} | ||
} // namespace __sanitizer | ||
#endif | ||
|
||
extern "C" void *emscripten_return_address(int level); | ||
|
||
#define INTERFACE extern "C" __attribute__((visibility("default"))) | ||
|
||
// FIXME: add caller pc to the error message (possibly as "ubsan: error-type | ||
// @1234ABCD"). | ||
#define HANDLER_RECOVER(name, msg) \ | ||
INTERFACE void __ubsan_handle_##name##_minimal() { \ | ||
if (!report_this_error(emscripten_return_address(0))) return; \ | ||
message("ubsan: " msg "\n"); \ | ||
} | ||
|
||
#define HANDLER_NORECOVER(name, msg) \ | ||
INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ | ||
message("ubsan: " msg "\n"); \ | ||
abort_with_message("ubsan: " msg); \ | ||
} | ||
|
||
#define HANDLER(name, msg) \ | ||
HANDLER_RECOVER(name, msg) \ | ||
HANDLER_NORECOVER(name, msg) | ||
|
||
HANDLER(type_mismatch, "type-mismatch") | ||
HANDLER(alignment_assumption, "alignment-assumption") | ||
HANDLER(add_overflow, "add-overflow") | ||
HANDLER(sub_overflow, "sub-overflow") | ||
HANDLER(mul_overflow, "mul-overflow") | ||
HANDLER(negate_overflow, "negate-overflow") | ||
HANDLER(divrem_overflow, "divrem-overflow") | ||
HANDLER(shift_out_of_bounds, "shift-out-of-bounds") | ||
HANDLER(out_of_bounds, "out-of-bounds") | ||
HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable") | ||
HANDLER_RECOVER(missing_return, "missing-return") | ||
HANDLER(vla_bound_not_positive, "vla-bound-not-positive") | ||
HANDLER(float_cast_overflow, "float-cast-overflow") | ||
HANDLER(load_invalid_value, "load-invalid-value") | ||
HANDLER(invalid_builtin, "invalid-builtin") | ||
HANDLER(function_type_mismatch, "function-type-mismatch") | ||
HANDLER(implicit_conversion, "implicit-conversion") | ||
HANDLER(nonnull_arg, "nonnull-arg") | ||
HANDLER(nonnull_return, "nonnull-return") | ||
HANDLER(nullability_arg, "nullability-arg") | ||
HANDLER(nullability_return, "nullability-return") | ||
HANDLER(pointer_overflow, "pointer-overflow") | ||
HANDLER(cfi_check_fail, "cfi-check-fail") |
Oops, something went wrong.