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 Dec 3, 2015
1 parent 64e5907 commit eafd435
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 9 deletions.
4 changes: 3 additions & 1 deletion src/ccall.cpp
Expand Up @@ -1269,7 +1269,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 @@ -1061,11 +1061,16 @@ static void raise_exception_unless(Value *cond, Value *exc, jl_codectx_t *ctx)
BasicBlock *passBB = BasicBlock::Create(getGlobalContext(),"pass");
builder.CreateCondBr(cond, passBB, failBB);
builder.SetInsertPoint(failBB);
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();
ctx->f->getBasicBlockList().push_back(passBB);
builder.SetInsertPoint(passBB);
Expand All @@ -1090,8 +1095,8 @@ static void raise_exception_if(Value *cond, GlobalVariable *exc, jl_codectx_t *c

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

static Value *boxed(const jl_cgval_t &v, jl_codectx_t *ctx, jl_value_t *jt=NULL);
Expand Down Expand Up @@ -1465,7 +1470,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_unless(ConstantInt::get(T_int1,0), prepare_global(jlundeferr_var), ctx);
raise_exception_unless(ConstantInt::get(T_int1,0), (Value*)NULL, ctx);
return jl_cgval_t(); // unreachable
}
if (type_is_ghost(elty))
Expand Down
3 changes: 0 additions & 3 deletions src/codegen.cpp
Expand Up @@ -448,7 +448,6 @@ static GlobalVariable *jlemptytuple_var;
static GlobalVariable *jlfloattemp_var;
#endif
static GlobalVariable *jldiverr_var;
static GlobalVariable *jlundeferr_var;
static GlobalVariable *jldomerr_var;
static GlobalVariable *jlovferr_var;
static GlobalVariable *jlinexacterr_var;
Expand Down Expand Up @@ -5626,8 +5625,6 @@ static void init_julia_llvm_env(Module *m)
jlemptytuple_var = global_to_llvm("jl_emptytuple", (void*)&jl_emptytuple, m);
jldiverr_var = global_to_llvm("jl_diverror_exception",
(void*)&jl_diverror_exception, m);
jlundeferr_var = global_to_llvm("jl_undefref_exception",
(void*)&jl_undefref_exception, m);
jldomerr_var = global_to_llvm("jl_domain_exception",
(void*)&jl_domain_exception, m);
jlovferr_var = global_to_llvm("jl_overflow_exception",
Expand Down
4 changes: 4 additions & 0 deletions src/signals-mach.c
Expand Up @@ -120,6 +120,10 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,
kern_return_t ret = thread_get_state(thread, x86_EXCEPTION_STATE64, (thread_state_t)&exc_state, &exc_count);
HANDLE_MACH_ERROR("thread_get_state", ret);
uint64_t fault_addr = exc_state.__faultvaddr;
if (!fault_addr) {
jl_throw_in_thread(0, thread, jl_undefref_exception);
return KERN_SUCCESS;
}
#ifdef SEGV_EXCEPTION
if (1) {
#else
Expand Down
6 changes: 6 additions & 0 deletions src/signals-unix.c
Expand Up @@ -88,6 +88,12 @@ static void segv_handler(int sig, siginfo_t *info, void *context)
sigprocmask(SIG_UNBLOCK, &sset, NULL);
jl_throw(jl_readonlymemory_exception);
}
else if (!info->si_addr) {
sigemptyset(&sset);
sigaddset(&sset, SIGSEGV);
sigprocmask(SIG_UNBLOCK, &sset, NULL);
jl_throw(jl_undefref_exception);
}
else {
#ifdef SEGV_EXCEPTION
sigemptyset(&sset);
Expand Down
5 changes: 5 additions & 0 deletions src/signals-win.c
Expand Up @@ -173,6 +173,11 @@ static LONG WINAPI _exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo,
jl_throw_in_ctx(jl_readonlymemory_exception, 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 @@ -3503,3 +3503,25 @@ let
finalize(obj)
@test finalized == 1
end

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 eafd435

Please sign in to comment.