diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp --- a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp @@ -210,10 +210,24 @@ } void CrashHandler(zx_handle_t *Event) { - // This structure is used to ensure we close handles to objects we create in - // this handler. - struct ScopedHandle { - ~ScopedHandle() { _zx_handle_close(Handle); } + // ScopedHandle is a helper class that makes sure handles are closed when they + // go out of scope. This also allows handles to be moved. + class ScopedHandle { + public: + ScopedHandle() { reset(); } + explicit ScopedHandle(zx_handle_t H) { reset(H); } + ScopedHandle(ScopedHandle &&Other) : Handle(Ohter.release()) {} + ScopedHandle &operator=(ScopedHandle &&Other) { + Handle = Other.release(); + return *this; + } + ScopedHandle(const ScopedHandle &Other) = delete; + ScopedHandle &operator=(const ScopedHandle &) = delete; + ~ScopedHandle() { reset(Handle); } + zx_handle_t release() { return std::exchange(Handle, ZX_HANDLE_INVALID); } + void reset(zx_handle_t H = ZX_HANDLE_INVALID) { + _zx_handle_close(std::exchange(Handle, H)); + } zx_handle_t Handle = ZX_HANDLE_INVALID; }; @@ -230,6 +244,14 @@ ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0), "_zx_object_signal"); + zx_koid_t crashed_tid = ZX_KOID_INVALID; + + // Multiple exceptions can be fired while handling the first exception + // unhandled_exceptions holds all the other exception handles so the + // other crashing threads are suspended until the first exception + // finishes. + std::vector unhandled_exceptions; + // This thread lives as long as the process in order to keep handling // crashes. In practice, the first crashed thread to reach the end of the // StaticCrashHandler will end the process. @@ -268,6 +290,26 @@ sizeof(GeneralRegisters)), "_zx_thread_read_state"); + if (crashed_tid != ZX_KOID_INVALID) { + // If we reach this point, it means that we received more than + // one exception. This new exception could either be from the + // same thread as the first exception or from another thread. + Printf("libFuzzer: An exception occurred while handling a previous " + "crash.\n"); + if (crashed_tid == ExceptionInfo.tid) { + // Exception came from the same thread. This means that the + // exception handling code crashed. This is bad. Generate a crashing + // artifact and exit. + exit(1); + } else { + // We received a crash from a different thread. Leave it suspended and + // wait for the next exception. + unhandled_exceptions.push_back(std::move(Exception)); + continue; + } + } + crashed_tid = ExceptionInfo.tid; + // To unwind properly, we need to push the crashing thread's register state // onto the stack and jump into a trampoline with CFI instructions on how // to restore it.