Skip to content

Commit

Permalink
Do not catch foreign exceptions in Pony try blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
Benoit Vey committed Jan 5, 2018
1 parent cdae272 commit 23b0087
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 17 deletions.
4 changes: 2 additions & 2 deletions src/libponyc/codegen/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,9 +796,9 @@ static void init_runtime(compile_t* c)
LLVMAddFunctionAttr(value, LLVMNoReturnAttribute);
#endif

// i32 pony_personality_v0(...)
// i32 ponyint_personality_v0(...)
type = LLVMFunctionType(c->i32, NULL, 0, true);
c->personality = LLVMAddFunction(c->module, "pony_personality_v0", type);
c->personality = LLVMAddFunction(c->module, "ponyint_personality_v0", type);

// i32 memcmp(i8*, i8*, intptr)
params[0] = c->void_ptr;
Expand Down
4 changes: 2 additions & 2 deletions src/libponyrt/lang/except_try_catch.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
; compatibility, please try to keep this file as minimal as possible in order
; to minimise the chances of breakage with newer LLVM versions.

declare i32 @pony_personality_v0(...)
declare i32 @ponyint_personality_v0(...)

define i1 @pony_try(void (i8*)* %fun, i8* %ctx) personality i32 (...)* @pony_personality_v0 {
define i1 @pony_try(void (i8*)* %fun, i8* %ctx) personality i32 (...)* @ponyint_personality_v0 {
entry:
invoke void %fun(i8* %ctx)
to label %post unwind label %unwind
Expand Down
24 changes: 15 additions & 9 deletions src/libponyrt/lang/posix_except.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
#include <unwind.h>
#include <stdlib.h>

PONY_EXTERN_C_BEGIN

#ifdef PLATFORM_IS_ARM
#include <string.h>
#include <stdio.h>
#define PONY_EXCEPTION_CLASS "Pony\0\0\0\0"
#else
#define PONY_EXCEPTION_CLASS 0x506F6E7900000000 // "Pony"
#endif

PONY_EXTERN_C_BEGIN

static __pony_thread_local struct _Unwind_Exception exception;
static __pony_thread_local uintptr_t landing_pad;

Expand All @@ -27,9 +29,9 @@ static void exception_cleanup(_Unwind_Reason_Code reason,
PONY_API void pony_error()
{
#ifdef PLATFORM_IS_ARM
memcpy(exception.exception_class, "Pony\0\0\0\0", 8);
memcpy(exception.exception_class, PONY_EXCEPTION_CLASS, 8);
#else
exception.exception_class = 0x506F6E7900000000; // "Pony"
exception.exception_class = PONY_EXCEPTION_CLASS;
#endif
exception.exception_cleanup = exception_cleanup;
_Unwind_RaiseException(&exception);
Expand Down Expand Up @@ -59,12 +61,15 @@ static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* exception,
return _URC_CONTINUE_UNWIND;
}

PONY_API _Unwind_Reason_Code pony_personality_v0(_Unwind_State state,
PONY_API _Unwind_Reason_Code ponyint_personality_v0(_Unwind_State state,
_Unwind_Exception* exception, _Unwind_Context* context)
{
if(exception == NULL || context == NULL)
return _URC_FAILURE;

if(memcmp(exception->exception_class, PONY_EXCEPTION_CLASS, 8) != 0)
return continue_unwind(exception, context);

// Save exception in r12.
_Unwind_SetGR(context, 12, (uintptr_t)exception);

Expand Down Expand Up @@ -116,15 +121,16 @@ PONY_API _Unwind_Reason_Code pony_personality_v0(_Unwind_State state,

#else

PONY_API _Unwind_Reason_Code pony_personality_v0(int version,
PONY_API _Unwind_Reason_Code ponyint_personality_v0(int version,
_Unwind_Action actions, uint64_t ex_class,
struct _Unwind_Exception* exception, struct _Unwind_Context* context)
{
(void)ex_class;

if(version != 1 || exception == NULL || context == NULL)
return _URC_FATAL_PHASE1_ERROR;

if(ex_class != PONY_EXCEPTION_CLASS)
return _URC_CONTINUE_UNWIND;

// The search phase sets up the landing pad.
if(actions & _UA_SEARCH_PHASE)
{
Expand Down
10 changes: 6 additions & 4 deletions src/libponyrt/lang/win_except.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,15 @@ PONY_API void pony_error()
* RtlUnwindEx does not ever return to its caller (i.e. this personality
* function). If it does, the process will (most likely) be terminated.
*/
PONY_API EXCEPTION_DISPOSITION pony_personality_v0(EXCEPTION_RECORD *ExcRecord,
void* EstablisherFrame, _CONTEXT *ContextRecord, DISPATCHER_CONTEXT* DispatcherContext)
PONY_API EXCEPTION_DISPOSITION ponyint_personality_v0(
EXCEPTION_RECORD *ExcRecord, void* EstablisherFrame, _CONTEXT *ContextRecord,
DISPATCHER_CONTEXT* DispatcherContext)
{
if(ExcRecord->ExceptionCode != PONY_EXCEPTION_CLASS || IS_UNWINDING(ExcRecord->ExceptionFlags))
if((ExcRecord->ExceptionCode != PONY_EXCEPTION_CLASS) ||
IS_UNWINDING(ExcRecord->ExceptionFlags))
return ExceptionContinueSearch;

if(!(ExcRecord->ExceptionFlags &
if(!(ExcRecord->ExceptionFlags &
(EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)))
{
if(!ponyint_lsda_scan(DispatcherContext, &landing_pad))
Expand Down
45 changes: 45 additions & 0 deletions test/libponyc/codegen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -473,3 +473,48 @@ EXPORT_SYMBOL char test_custom_serialisation_compare(uint64_t* p1, uint64_t* p2)
}

}


TEST_F(CodegenTest, TryBlockCantCatchCppExcept)
{
const char* src =
"actor Main\n"
" new create(env: Env) =>\n"
" let r = @codegen_test_tryblock_catch[I32](this~tryblock())\n"
" @pony_exitcode[I32](r)\n"

" fun @tryblock() =>\n"
" try\n"
" @codegen_test_tryblock_throw[None]()?\n"
" else\n"
" None\n"
" end";

TEST_COMPILE(src);

int exit_code = 0;
ASSERT_TRUE(run_program(&exit_code));
ASSERT_EQ(exit_code, 1);
}


extern "C"
{

EXPORT_SYMBOL int codegen_test_tryblock_catch(void (*callback)())
{
try
{
callback();
return 0;
} catch(std::exception const&) {
return 1;
}
}

EXPORT_SYMBOL bool codegen_test_tryblock_throw()
{
throw std::exception{};
}

}
9 changes: 9 additions & 0 deletions test/libponyrt/lang/error.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <pony.h>

#include <exception>

TEST(ErrorTest, PonyTry)
{
auto cb_success = [](void*){};
Expand All @@ -11,3 +13,10 @@ TEST(ErrorTest, PonyTry)
ASSERT_TRUE(pony_try(cb_success, nullptr));
ASSERT_FALSE(pony_try(cb_error, nullptr));
}

TEST(ErrorTest, PonyTryCantCatchCppExcept)
{
auto cb_cppthrow = [](void*){ throw std::exception{}; };

ASSERT_THROW((pony_try(cb_cppthrow, nullptr)), std::exception);
}

0 comments on commit 23b0087

Please sign in to comment.