From 64dad88a32b7f6d4767e992963d5d24921adfc40 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 23 Jul 2020 14:03:23 +0800 Subject: [PATCH] Kernel exception: fixed top level finally. (#70) Fixes #70. --- src/llvm_libunwind/src/Unwind-EHABI.cpp | 5 +++++ src/runtime/src/eh_artiq.rs | 21 +++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/llvm_libunwind/src/Unwind-EHABI.cpp b/src/llvm_libunwind/src/Unwind-EHABI.cpp index bfa4b30..14bc15f 100644 --- a/src/llvm_libunwind/src/Unwind-EHABI.cpp +++ b/src/llvm_libunwind/src/Unwind-EHABI.cpp @@ -551,6 +551,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor static_cast(exception_object)); int frame_count = 0; + unw_word_t prev_sp = 0x0; // Walk each frame until we reach where search phase said to stop. while (true) { // Ask libunwind to get next frame (skip over first which is @@ -576,6 +577,10 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor unw_word_t sp; unw_proc_info_t frameInfo; __unw_get_reg(cursor, UNW_REG_SP, &sp); + if (sp == prev_sp) { + return _URC_END_OF_STACK; + } + prev_sp = sp; if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): __unw_get_proc_info " diff --git a/src/runtime/src/eh_artiq.rs b/src/runtime/src/eh_artiq.rs index f4ca871..4193851 100644 --- a/src/runtime/src/eh_artiq.rs +++ b/src/runtime/src/eh_artiq.rs @@ -128,8 +128,15 @@ pub unsafe fn artiq_personality(state: uw::_Unwind_State, let exception = &exception_info.exception.unwrap(); if search_phase { match eh_action { - EHAction::None | - EHAction::Cleanup(_) => return continue_unwind(exception_object, context), + EHAction::None => return continue_unwind(exception_object, context), + // Actually, cleanup should not return handler found, this is to workaround + // the issue of terminating directly when no catch cause is found while + // having some cleanup routines defined by finally. + // The best way to handle this is to force unwind the stack in the raise + // function when end of stack is reached, and call terminate at the end of + // the unwind. Unfortunately, there is no forced unwind function defined + // for EHABI, and I have no idea how to implement that, so this is a hack. + EHAction::Cleanup(_) => return uw::_URC_HANDLER_FOUND, EHAction::Catch(_) => { // EHABI requires the personality routine to update the // SP value in the barrier cache of the exception object. @@ -195,10 +202,9 @@ static mut INFLIGHT: ExceptionInfo = ExceptionInfo { }; pub unsafe extern fn raise(exception: *const Exception) -> ! { - // Zing! The Exception<'a> to Exception<'static> transmute is not really sound in case - // the exception is ever captured. Fortunately, they currently aren't, and we save - // on the hassle of having to allocate exceptions somewhere except on stack. trace!("Trying to raise exception"); + // FIXME: unsound transmute + // This would cause stack memory corruption. INFLIGHT.exception = Some(mem::transmute::>(*exception)); INFLIGHT.handled = false; @@ -219,9 +225,8 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! { pub unsafe extern fn reraise() -> ! { use cslice::AsCSlice; - trace!("Re-raise"); - // current implementation uses raise as _Unwind_Resume is not working now - // would debug that later. + // Reraise is basically cxa_rethrow, which calls _Unwind_Resume_or_Rethrow, + // which for EHABI would always call _Unwind_RaiseException. match INFLIGHT.exception { Some(ref exception) => raise(exception), None => raise(&Exception {