a013de84e0
Commit 18bdb28ef6 have configured `SIGPROF` handler on Android
to use alternative signal stack to workaround a [bug][1] in Bionic
implementation of `setjmp`. However when implementing the
workaround we have misinterpreted `sigaltstack` documentation
and assumed that `sigaltstack` configures alternative stack
*globally*, similar to how `sigaction` configures the signal handler.
This is not correct: `sigaltstack` configures alternative stack
for the current thread only.
Nevertheless our workaround kinda worked as intended because Bionic's
`pthread_create` actually assigns an individual alternative
stack to each new thread since [Android L][2].
However older version of Bionic (pre [Android 6.0.1][3]) configured
alternative signal stack which was too small for ARM64. This meant
that non-trivial signal handler could easily overflow the stack
and cause a SIGSEGV when hitting a guard page.
This is what we observe in the flutter/flutter#130003: launching
Flutter application with profiler enabled in a ARM64 emulator
running Android 6.0 causes an immediate segfault in the
signal handler.
This CL changes our code to make sure that alternative signal
stack associated with the current thread is present and is large
enough and allocate a new one if it is not.
[1]: b/152210274
[2]: https://android-review.git.corp.google.com/c/platform/bionic/+/62238
[3]: https://android-review.git.corp.google.com/c/platform/bionic/+/172213
[4]: https://github.com/flutter/flutter/issues/130003
TEST=manually on an Android 6.0.0 ARM64 emulator
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-ffi-android-release-arm64c-try,vm-ffi-android-release-arm-try
Change-Id: Ib87df25e72ad3f486e90cf2fc6d7f980a8e0b1dc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327866
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
73 lines
1.8 KiB
C++
73 lines
1.8 KiB
C++
// Copyright (c) 2013, 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_VM_THREAD_INTERRUPTER_H_
|
|
#define RUNTIME_VM_THREAD_INTERRUPTER_H_
|
|
|
|
#include "vm/allocation.h"
|
|
#include "vm/os_thread.h"
|
|
#include "vm/signal_handler.h"
|
|
#include "vm/thread.h"
|
|
|
|
namespace dart {
|
|
|
|
struct InterruptedThreadState {
|
|
uintptr_t pc;
|
|
uintptr_t csp;
|
|
uintptr_t dsp;
|
|
uintptr_t fp;
|
|
uintptr_t lr;
|
|
};
|
|
|
|
class ThreadInterrupter : public AllStatic {
|
|
public:
|
|
static void Init();
|
|
|
|
static void Startup();
|
|
static void Cleanup();
|
|
|
|
// Delay between interrupts.
|
|
static void SetInterruptPeriod(intptr_t period);
|
|
|
|
// Wake up the thread interrupter thread.
|
|
static void WakeUp();
|
|
|
|
// Interrupt a thread.
|
|
static void InterruptThread(OSThread* thread);
|
|
|
|
// Prepare current thread for handling interrupts. Returns
|
|
// opaque pointer to the allocated state (if any).
|
|
static void* PrepareCurrentThread();
|
|
|
|
// Cleanup any state which was created by |PrepareCurrentThread|.
|
|
static void CleanupCurrentThreadState(void* state);
|
|
|
|
private:
|
|
static constexpr intptr_t kMaxThreads = 4096;
|
|
static bool initialized_;
|
|
static bool shutdown_;
|
|
static bool thread_running_;
|
|
static bool woken_up_;
|
|
static ThreadJoinId interrupter_thread_id_;
|
|
static Monitor* monitor_;
|
|
static intptr_t interrupt_period_;
|
|
static intptr_t current_wait_time_;
|
|
|
|
static bool InDeepSleep() {
|
|
return current_wait_time_ == Monitor::kNoTimeout;
|
|
}
|
|
|
|
static void ThreadMain(uword parameters);
|
|
|
|
static void InstallSignalHandler();
|
|
|
|
static void RemoveSignalHandler();
|
|
|
|
friend class ThreadInterrupterVisitIsolates;
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_THREAD_INTERRUPTER_H_
|