authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-20 17:48:24-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-20 17:48:24-04:00
log257fded70cc456f0c4c2a56f845cf7f21e738674
treebb2ab8d0f241b7c37ef2d99ff5b798dde4edfa48
parentf663bcd6b2ff8186e13b6826318fa3c8e72a9ff9
signaturelock-open Commit is signed but in an unrecognized format.

avoid setting `tail` for `@panic`

Currently, slices are passed via reference, even though it would be better to pass the ptr and len as separate arguments (#561). This means that any function call with a slice parameter cannot be a tail call, because according to LLVM spec: > Both [tail,musttail] markers imply that the callee does not access > allocas from the caller There was one other place we were setting `tail` and I made that conditional on whether or not the argument referenced allocas in the caller. This was causing undefined behavior in the compiler when it hit asserts, causing it to print garbage memory to the terminal. See #3262 for example.

1 files changed, 47 insertions(+), 17 deletions(-)

src/codegen.cpp+47-17
......@@ -964,7 +964,9 @@ static ZigType *ptr_to_stack_trace_type(CodeGen *g) {
964964 return get_pointer_to_type(g, get_stack_trace_type(g), false);
965965}
966966
967static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
967static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg,
968 bool stack_trace_is_llvm_alloca)
969{
968970 assert(g->panic_fn != nullptr);
969971 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
970972 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
......@@ -975,14 +977,20 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace
975977 msg_arg,
976978 stack_trace_arg,
977979 };
978 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
979 LLVMSetTailCall(call_instruction, true);
980 ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
981 if (!stack_trace_is_llvm_alloca) {
982 // The stack trace argument is not in the stack of the caller, so
983 // we'd like to set tail call here, but because slices (the type of msg_arg) are
984 // still passed as pointers (see https://github.com/ziglang/zig/issues/561) we still
985 // cannot make this a tail call.
986 //LLVMSetTailCall(call_instruction, true);
987 }
980988 LLVMBuildUnreachable(g->builder);
981989}
982990
983991// TODO update most callsites to call gen_assertion instead of this
984992static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {
985 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
993 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr, false);
986994}
987995
988996static void gen_assertion_scope(CodeGen *g, PanicMsgId msg_id, Scope *source_scope) {
......@@ -1320,7 +1328,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
13201328 gen_store_untyped(g, slice_len, msg_slice_len_field_ptr, 0, false);
13211329
13221330 // Call panic()
1323 gen_panic(g, msg_slice, err_ret_trace_arg);
1331 gen_panic(g, msg_slice, err_ret_trace_arg, false);
13241332
13251333 LLVMPositionBuilderAtEnd(g->builder, prev_block);
13261334 if (!g->strip_debug_symbols) {
......@@ -1331,21 +1339,25 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
13311339 return fn_val;
13321340}
13331341
1334static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {
1342static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope, bool *is_llvm_alloca) {
13351343 if (!g->have_err_ret_tracing) {
1344 *is_llvm_alloca = false;
13361345 return nullptr;
13371346 }
13381347 if (g->cur_err_ret_trace_val_stack != nullptr) {
1348 *is_llvm_alloca = !fn_is_async(g->cur_fn);
13391349 return g->cur_err_ret_trace_val_stack;
13401350 }
1351 *is_llvm_alloca = false;
13411352 return g->cur_err_ret_trace_val_arg;
13421353}
13431354
13441355static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) {
13451356 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
13461357 LLVMValueRef call_instruction;
1358 bool is_llvm_alloca = false;
13471359 if (g->have_err_ret_tracing) {
1348 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
1360 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope, &is_llvm_alloca);
13491361 if (err_ret_trace_val == nullptr) {
13501362 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
13511363 }
......@@ -1362,7 +1374,9 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc
13621374 call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 1,
13631375 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
13641376 }
1365 LLVMSetTailCall(call_instruction, true);
1377 if (!is_llvm_alloca) {
1378 LLVMSetTailCall(call_instruction, true);
1379 }
13661380 LLVMBuildUnreachable(g->builder);
13671381}
13681382
......@@ -2202,7 +2216,9 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
22022216 assert(g->have_err_ret_tracing);
22032217
22042218 LLVMValueRef return_err_fn = get_return_err_fn(g);
2205 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope);
2219 bool is_llvm_alloca;
2220 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope,
2221 &is_llvm_alloca);
22062222 ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1,
22072223 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
22082224
......@@ -2256,6 +2272,10 @@ static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) {
22562272 return resume_bb;
22572273}
22582274
2275// Be careful setting tail call. According to LLVM lang ref,
2276// tail and musttail imply that the callee does not access allocas from the caller.
2277// This works for async functions since the locals are spilled.
2278// http://llvm.org/docs/LangRef.html#id320
22592279static void set_tail_call_if_appropriate(CodeGen *g, LLVMValueRef call_inst) {
22602280 LLVMSetTailCall(call_inst, true);
22612281}
......@@ -2361,7 +2381,8 @@ static void gen_async_return(CodeGen *g, IrInstructionReturn *instruction) {
23612381 LLVMValueRef awaiter_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
23622382 frame_index_trace_arg(g, ret_type) + 1, "");
23632383 LLVMValueRef dest_trace_ptr = LLVMBuildLoad(g->builder, awaiter_trace_ptr_ptr, "");
2364 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
2384 bool is_llvm_alloca;
2385 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca);
23652386 LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val };
23662387 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
23672388 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
......@@ -3967,7 +3988,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
39673988 if (prefix_arg_err_ret_stack) {
39683989 LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
39693990 frame_index_trace_arg(g, src_return_type) + 1, "");
3970 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
3991 bool is_llvm_alloca;
3992 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope,
3993 &is_llvm_alloca);
39713994 LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr);
39723995 }
39733996 }
......@@ -4024,7 +4047,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
40244047
40254048 gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr);
40264049
4027 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
4050 bool is_llvm_alloca;
4051 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca));
40284052 }
40294053 }
40304054 } else {
......@@ -4032,7 +4056,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
40324056 gen_param_values.append(result_loc);
40334057 }
40344058 if (prefix_arg_err_ret_stack) {
4035 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
4059 bool is_llvm_alloca;
4060 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca));
40364061 }
40374062 }
40384063 FnWalk fn_walk = {};
......@@ -4912,7 +4937,8 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
49124937static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,
49134938 IrInstructionErrorReturnTrace *instruction)
49144939{
4915 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
4940 bool is_llvm_alloca;
4941 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca);
49164942 if (cur_err_ret_trace_val == nullptr) {
49174943 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
49184944 }
......@@ -5496,7 +5522,9 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir
54965522}
54975523
54985524static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
5499 gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope));
5525 bool is_llvm_alloca;
5526 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca);
5527 gen_panic(g, ir_llvm_value(g, instruction->msg), err_ret_trace_val, is_llvm_alloca);
55005528 return nullptr;
55015529}
55025530
......@@ -5753,7 +5781,8 @@ static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstruction *source_ins
57535781 LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
57545782 frame_index_trace_arg(g, result_type), "");
57555783 LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, "");
5756 LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope);
5784 bool is_llvm_alloca;
5785 LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope, &is_llvm_alloca);
57575786 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
57585787 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
57595788 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
......@@ -5802,7 +5831,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst
58025831
58035832 // supply the error return trace pointer
58045833 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
5805 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
5834 bool is_llvm_alloca;
5835 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca);
58065836 assert(my_err_ret_trace_val != nullptr);
58075837 LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
58085838 frame_index_trace_arg(g, result_type) + 1, "");