mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:30:32 +00:00
228c52ed4a
TSAN instruments C++ code by adding prologue/epilogue code which maintains a shadow stack. Using setjmp()/longjmp() is intercepted by TSAN and correspondingly unwinds the shadow stack. When Dart VM throws exceptions we call the JumpToFrame stub from C++ which will directly reset the stack to the exception handler catch entry. This leaves the TSAN shadow stack unchanged. This means whenever an exception is thrown we leak frames in TSAN's shadow stack. Due to using a fixed-size shadow stack, it will cause a buffer-overflow in TSAN when too many such frame leaks happen. This can cause arbitrary memory to be overriden, leading to awkward crashes. This is especially an issue on the "iso-stres" builder because it launches - in the same process - *many* small tests, more easily hitting that limit. This CL will workaround the TSAN issue by making runtime call save it's state via setjmp() and make exception throughing process go via longjmp() (which TSAN will intercept) before actually calling the JumpToFrame stub. => This will ensure the TSAN shadow stack is correctly maintained. The [jmp_buf]'s encoding of register state is non-trivial (e.g. it uses XOR'ing of the actual saved state under certain glibc versions). So we store any state we need to pass to the target of the `longjmp()` on the [Thread] instead of overriding the [jmp_buf]s register state with the arguments. Issue https://github.com/dart-lang/sdk/issues/47472#issuecomment-948235479 TEST=vm/dart{,_2}/regress47472_test.dart Change-Id: Ifbf6580aa15bcce54d0584cdc3cd18cc19be0a9c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/222300 Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
37 lines
945 B
C
37 lines
945 B
C
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef RUNTIME_PLATFORM_THREAD_SANITIZER_H_
|
|
#define RUNTIME_PLATFORM_THREAD_SANITIZER_H_
|
|
|
|
#include "platform/globals.h"
|
|
|
|
#if defined(__has_feature)
|
|
#if __has_feature(thread_sanitizer)
|
|
#define USING_THREAD_SANITIZER
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(USING_THREAD_SANITIZER)
|
|
#define NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
|
|
extern "C" void __tsan_acquire(void* addr);
|
|
extern "C" void __tsan_release(void* addr);
|
|
#else
|
|
#define NO_SANITIZE_THREAD
|
|
#endif
|
|
|
|
#if defined(USING_THREAD_SANITIZER)
|
|
#define DO_IF_TSAN(CODE) CODE
|
|
#else
|
|
#define DO_IF_TSAN(CODE)
|
|
#endif
|
|
|
|
#if defined(USING_THREAD_SANITIZER)
|
|
#define DO_IF_NOT_TSAN(CODE)
|
|
#else
|
|
#define DO_IF_NOT_TSAN(CODE) CODE
|
|
#endif
|
|
|
|
#endif // RUNTIME_PLATFORM_THREAD_SANITIZER_H_
|