Skip to content

Commit

Permalink
Raise UndefRefError using SegFault handler
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyichao committed Jul 31, 2016
1 parent ca355ff commit b26c5dd
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 14 deletions.
4 changes: 3 additions & 1 deletion src/ccall.cpp
Expand Up @@ -1699,7 +1699,9 @@ static jl_cgval_t emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
FunctionType *functype = FunctionType::get(sret ? T_void : prt, fargt_sig, isVa);

if (jl_ptr != NULL) {
null_pointer_check(jl_ptr,ctx);
// null_pointer_check(jl_ptr, ctx);
// We throw a UndefRefError in the SegFault handler if the pointer is
// NULL.
Type *funcptype = PointerType::get(functype,0);
llvmf = builder.CreateIntToPtr(jl_ptr, funcptype);
}
Expand Down
15 changes: 10 additions & 5 deletions src/cgutils.cpp
Expand Up @@ -628,11 +628,16 @@ static void error_unless(Value *cond, const std::string &msg, jl_codectx_t *ctx)
static void raise_exception(Value *exc, jl_codectx_t *ctx,
BasicBlock *contBB=nullptr)
{
if (exc) {
#ifdef LLVM37
builder.CreateCall(prepare_call(jlthrow_func), { exc });
builder.CreateCall(prepare_call(jlthrow_func), { exc });
#else
builder.CreateCall(prepare_call(jlthrow_func), exc);
builder.CreateCall(prepare_call(jlthrow_func), exc);
#endif
}
else {
builder.CreateLoad(Constant::getNullValue(T_ppint8), true);
}
builder.CreateUnreachable();
if (!contBB) {
contBB = BasicBlock::Create(jl_LLVMContext, "after_throw", ctx->f);
Expand Down Expand Up @@ -662,8 +667,8 @@ static void raise_exception_if(Value *cond, Value *exc, jl_codectx_t *ctx)

static void null_pointer_check(Value *v, jl_codectx_t *ctx)
{
raise_exception_unless(builder.CreateICmpNE(v,Constant::getNullValue(v->getType())),
literal_pointer_val(jl_undefref_exception), ctx);
raise_exception_unless(builder.CreateICmpNE(v, Constant::getNullValue(v->getType())),
(Value*)NULL, ctx);
}

static void emit_type_error(const jl_cgval_t &x, jl_value_t *type, const std::string &msg,
Expand Down Expand Up @@ -1048,7 +1053,7 @@ static jl_cgval_t emit_getfield_knownidx(const jl_cgval_t &strct, unsigned idx,
Type *elty = julia_type_to_llvm(jfty);
assert(elty != NULL);
if (jfty == jl_bottom_type) {
raise_exception(literal_pointer_val(jl_undefref_exception), ctx);
raise_exception((Value*)NULL, ctx);
return jl_cgval_t(); // unreachable
}
if (type_is_ghost(elty))
Expand Down
12 changes: 12 additions & 0 deletions src/signals-mach.c
Expand Up @@ -126,6 +126,14 @@ void jl_throw_in_thread(int tid, mach_port_t thread, jl_value_t *exception)
x86_thread_state64_t state;
kern_return_t ret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&state, &count);
HANDLE_MACH_ERROR("thread_get_state", ret);

if (exception == jl_undefref_exception && !state.__rip) {
uintptr_t rsp = state.__rsp;
state.__rip = *(uintptr_t*)rsp;
rsp += sizeof(void*);
state.__rsp = rsp;
}

jl_ptls_t ptls2 = jl_all_tls_states[tid];

ptls2->bt_size = rec_backtrace_ctx(ptls2->bt_data, JL_MAX_BT_SIZE,
Expand Down Expand Up @@ -204,6 +212,10 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,
}
return KERN_SUCCESS;
}
if (!fault_addr) {
jl_throw_in_thread(tid, thread, jl_undefref_exception);
return KERN_SUCCESS;
}
#ifdef SEGV_EXCEPTION
if (1) {
#else
Expand Down
32 changes: 32 additions & 0 deletions src/signals-unix.c
Expand Up @@ -134,6 +134,38 @@ static void segv_handler(int sig, siginfo_t *info, void *context)
jl_unblock_signal(sig);
jl_throw_in_ctx(jl_readonlymemory_exception, context);
}
else if (!info->si_addr) {
jl_unblock_signal(sig);
#ifdef _OS_LINUX_
ucontext_t *ctx = (ucontext_t*)context;
# if defined(_CPU_X86_64_)
uintptr_t pc = ctx->uc_mcontext.gregs[REG_RIP];
if (!pc) {
uintptr_t rsp = ctx->uc_mcontext.gregs[REG_RSP];
ctx->uc_mcontext.gregs[REG_RIP] = *(uintptr_t*)rsp;
rsp += sizeof(void*);
ctx->uc_mcontext.gregs[REG_RSP] = rsp;
}
# elif defined(_CPU_X86_)
uintptr_t pc = ctx->uc_mcontext.gregs[REG_EIP];
if (!pc) {
uintptr_t rsp = ctx->uc_mcontext.gregs[REG_ESP];
ctx->uc_mcontext.gregs[REG_EIP] = *(uintptr_t*)rsp;
rsp += sizeof(void*);
ctx->uc_mcontext.gregs[REG_ESP] = rsp;
}
# elif defined(_CPU_AARCH64_)
uintptr_t pc = ctx->uc_mcontext.pc;
if (!pc)
ctx->uc_mcontext.pc = ctx->uc_mcontext.regs[29]; // link register
# elif defined(_CPU_ARM_)
uintptr_t pc = ctx->uc_mcontext.arm_pc;
if (!pc)
ctx->uc_mcontext.arm_pc = ctx->uc_mcontext.arm_lr;
# endif
#endif
jl_throw_in_ctx(jl_undefref_exception, context);
}
else {
#ifdef SEGV_EXCEPTION
jl_unblock_signal(sig);
Expand Down
34 changes: 26 additions & 8 deletions src/signals-win.c
Expand Up @@ -105,23 +105,36 @@ void jl_throw_in_ctx(jl_value_t *excpt, CONTEXT *ctxThread, int bt)
jl_ptls_t ptls = jl_get_ptls_states();
assert(excpt != NULL);
#if defined(_CPU_X86_64_)
DWORD64 Rsp = (ctxThread->Rsp&(DWORD64)-16) - 8;
uintptr_t pc = ctxThread->Rip;
if (excpt == jl_undefref_exception && !pc) {
uintptr_t sp = ctxThread->Rsp;
ctxThread->Rip = *(uintptr_t*)sp;
sp += sizeof(void*);
ctxThread->Rsp = sp;
}
uintptr_t sp = (ctxThread->Rsp & (uintptr_t)-16) - sizeof(void*);
#elif defined(_CPU_X86_)
DWORD32 Esp = (ctxThread->Esp&(DWORD32)-16) - 4;
uintptr_t pc = ctxThread->Eip;
if (excpt == jl_undefref_exception && !pc) {
uintptr_t sp = ctxThread->Esp;
ctxThread->Eip = *(uintptr_t*)sp;
sp += sizeof(void*);
ctxThread->Esp = sp;
}
uintptr_t sp = (ctxThread->Esp & (uintptr_t)-16) - sizeof(void*);
#else
#error WIN16 not supported :P
#endif
ptls->bt_size = bt ? rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE,
ctxThread) : 0;
ptls->exception_in_transit = excpt;
*(uintptr_t*)sp = 0;
#if defined(_CPU_X86_64_)
*(DWORD64*)Rsp = 0;
ctxThread->Rsp = Rsp;
ctxThread->Rip = (DWORD64)&jl_rethrow;
ctxThread->Rsp = sp;
ctxThread->Rip = (uintptr_t)&jl_rethrow;
#elif defined(_CPU_X86_)
*(DWORD32*)Esp = 0;
ctxThread->Esp = Esp;
ctxThread->Eip = (DWORD)&jl_rethrow;
ctxThread->Esp = sp;
ctxThread->Eip = (uintptr_t)&jl_rethrow;
#endif
}

Expand Down Expand Up @@ -221,6 +234,11 @@ static LONG WINAPI _exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo,
ExceptionInfo->ContextRecord,in_ctx);
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (!ExceptionInfo->ExceptionRecord->ExceptionInformation[1]) {
jl_throw_in_ctx(jl_undefref_exception,
ExceptionInfo->ContextRecord, in_ctx);
return EXCEPTION_CONTINUE_EXECUTION;
}
}
jl_safe_printf("\nPlease submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.\nException: ");
switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
Expand Down
22 changes: 22 additions & 0 deletions test/core.jl
Expand Up @@ -4461,3 +4461,25 @@ end
#end
#@test local_innersig(Int32(2)) == ((Int32(2), Int32(1), Int32(2)im), (Int32(2), UInt32(1)))
#@test local_innersig(Int64(3)) == ((Int64(3), Int64(1), Int64(3)im), (Int64(3), UInt64(1)))

module TestUndefRefErrors14147

using Base.Test

# Test different kinds of UndefRefError
call_fptr(p) = ccall(p, Int, ())
return_int_function() = 100
@test call_fptr(cfunction(return_int_function, Int, Tuple{})) == 100
@test_throws UndefRefError call_fptr(C_NULL)

type TypeWithUndefField
a
TypeWithUndefField() = new()
end
copy_undef_field(a, b) = (a.a = b.a)
get_undef_field(a) = a.a
@test_throws UndefRefError copy_undef_field(TypeWithUndefField(),
TypeWithUndefField())
@test_throws UndefRefError get_undef_field(TypeWithUndefField())

end

0 comments on commit b26c5dd

Please sign in to comment.