Skip to content

Commit

Permalink
Emit traps for unreachable nodes (JuliaLang#41465)
Browse files Browse the repository at this point in the history
Raw `unreachable` in LLVM is somewhat dangerous since LLVM will literally
stop emitting code there, so if the unreachable is wrong, execution will
crash into whatever subsequent code exists, causing strange and mysterious
errors and incorrect backtraces that are hard to debug without rr. As a
result, we basically always emit a safety trap call before an `unreachable`
terminator, which will abort execution at the point where unreachable was
executed and at least provide proper backtraces. However, we neglected
to do this for literal unreachables that came from Julia IR (i.e. ReturnNodes
with undef val field). Fix that to make debugging easier if unreachable
ever gets accidentally executed.
  • Loading branch information
Keno authored Jul 6, 2021
1 parent f4c85c1 commit c73901e
Showing 1 changed file with 14 additions and 9 deletions.
23 changes: 14 additions & 9 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,7 @@ static void allocate_gc_frame(jl_codectx_t &ctx, BasicBlock *b0);
static Value *get_current_task(jl_codectx_t &ctx);
static Value *get_current_ptls(jl_codectx_t &ctx);
static Value *get_current_signal_page(jl_codectx_t &ctx);
static void CreateTrap(IRBuilder<> &irbuilder);
static void CreateTrap(IRBuilder<> &irbuilder, bool create_new_block = true);
static CallInst *emit_jlcall(jl_codectx_t &ctx, Function *theFptr, Value *theF,
jl_cgval_t *args, size_t nargs, CallingConv::ID cc);
static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction *theFptr, Value *theF,
Expand Down Expand Up @@ -1456,16 +1456,21 @@ static Constant *undef_value_for_type(Type *T) {
return undef;
}

static void CreateTrap(IRBuilder<> &irbuilder)
static void CreateTrap(IRBuilder<> &irbuilder, bool create_new_block)
{
Function *f = irbuilder.GetInsertBlock()->getParent();
Function *trap_func = Intrinsic::getDeclaration(
f->getParent(),
Intrinsic::trap);
irbuilder.CreateCall(trap_func);
irbuilder.CreateUnreachable();
BasicBlock *newBB = BasicBlock::Create(irbuilder.getContext(), "after_noret", f);
irbuilder.SetInsertPoint(newBB);
if (create_new_block) {
BasicBlock *newBB = BasicBlock::Create(irbuilder.getContext(), "after_noret", f);
irbuilder.SetInsertPoint(newBB);
}
else {
irbuilder.ClearInsertionPoint();
}
}

#if 0 // this code is likely useful, but currently unused
Expand Down Expand Up @@ -6901,8 +6906,8 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
if (seq_next >= 0 && (unsigned)seq_next < stmtslen) {
workstack.push_back(seq_next);
}
else if (!ctx.builder.GetInsertBlock()->getTerminator()) {
ctx.builder.CreateUnreachable();
else if (ctx.builder.GetInsertBlock() && !ctx.builder.GetInsertBlock()->getTerminator()) {
CreateTrap(ctx.builder, false);
}
while (!workstack.empty()) {
int item = workstack.back();
Expand All @@ -6912,7 +6917,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
cursor = item;
return;
}
if (seq_next != -1 && !ctx.builder.GetInsertBlock()->getTerminator()) {
if (seq_next != -1 && ctx.builder.GetInsertBlock() && !ctx.builder.GetInsertBlock()->getTerminator()) {
come_from_bb[cursor + 1] = ctx.builder.GetInsertBlock();
ctx.builder.CreateBr(nextbb->second);
}
Expand Down Expand Up @@ -7050,7 +7055,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
if (jl_is_returnnode(stmt)) {
jl_value_t *retexpr = jl_returnnode_value(stmt);
if (retexpr == NULL) {
ctx.builder.CreateUnreachable();
CreateTrap(ctx.builder, false);
find_next_stmt(-1);
continue;
}
Expand All @@ -7059,7 +7064,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
jl_cgval_t retvalinfo = emit_expr(ctx, retexpr);
retvalinfo = convert_julia_type(ctx, retvalinfo, jlrettype);
if (retvalinfo.typ == jl_bottom_type) {
ctx.builder.CreateUnreachable();
CreateTrap(ctx.builder, false);
find_next_stmt(-1);
continue;
}
Expand Down

0 comments on commit c73901e

Please sign in to comment.