authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-06 18:47:09-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-06 18:47:09-04:00
log966c9ea63c635a12c923d3ab155a9070affb18c5
tree114dd3ccaf6b17b1d71febb9277dc30fb4eaf68d
parent17199b087915661c935f0970cc1e4eb29968a68d
signature Commit is signed but in an unrecognized format.

error return trace across suspend points


3 files changed, 158 insertions(+), 10 deletions(-)

src/all_types.hpp+1
...@@ -1737,6 +1737,7 @@ struct CodeGen {...@@ -1737,6 +1737,7 @@ struct CodeGen {
1737 LLVMValueRef stacksave_fn_val;1737 LLVMValueRef stacksave_fn_val;
1738 LLVMValueRef stackrestore_fn_val;1738 LLVMValueRef stackrestore_fn_val;
1739 LLVMValueRef write_register_fn_val;1739 LLVMValueRef write_register_fn_val;
1740 LLVMValueRef merge_err_ret_traces_fn_val;
1740 LLVMValueRef sp_md_node;1741 LLVMValueRef sp_md_node;
1741 LLVMValueRef err_name_table;1742 LLVMValueRef err_name_table;
1742 LLVMValueRef safety_crash_err_fn;1743 LLVMValueRef safety_crash_err_fn;
src/codegen.cpp+146-5
...@@ -2026,18 +2026,159 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {...@@ -2026,18 +2026,159 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2026 }2026 }
2027}2027}
20282028
2029static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
2030 if (g->merge_err_ret_traces_fn_val)
2031 return g->merge_err_ret_traces_fn_val;
2032
2033 assert(g->stack_trace_type != nullptr);
2034
2035 LLVMTypeRef param_types[] = {
2036 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
2037 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
2038 };
2039 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
2040
2041 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
2042 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
2043 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
2044 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
2045 addLLVMFnAttr(fn_val, "nounwind");
2046 add_uwtable_attr(g, fn_val);
2047 // Error return trace memory is in the stack, which is impossible to be at address 0
2048 // on any architecture.
2049 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
2050 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
2051 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
2052 // Error return trace memory is in the stack, which is impossible to be at address 0
2053 // on any architecture.
2054 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
2055 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
2056 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
2057 if (g->build_mode == BuildModeDebug) {
2058 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
2059 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
2060 }
2061
2062 // this is above the ZigLLVMClearCurrentDebugLocation
2063 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
2064
2065 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
2066 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
2067 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
2068 LLVMPositionBuilderAtEnd(g->builder, entry_block);
2069 ZigLLVMClearCurrentDebugLocation(g->builder);
2070
2071 // var frame_index: usize = undefined;
2072 // var frames_left: usize = undefined;
2073 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
2074 // frame_index = 0;
2075 // frames_left = src_stack_trace.index;
2076 // if (frames_left == 0) return;
2077 // } else {
2078 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
2079 // frames_left = src_stack_trace.instruction_addresses.len;
2080 // }
2081 // while (true) {
2082 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
2083 // frames_left -= 1;
2084 // if (frames_left == 0) return;
2085 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
2086 // }
2087 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
2088
2089 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index");
2090 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left");
2091
2092 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
2093 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
2094
2095 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
2096 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
2097 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
2098 (unsigned)src_index_field_index, "");
2099 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
2100 (unsigned)src_addresses_field_index, "");
2101 ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
2102 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
2103 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
2104 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
2105 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
2106 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
2107 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
2108 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
2109 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
2110 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
2111 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
2112 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
2113 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
2114
2115 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
2116 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
2117 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
2118 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
2119 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
2120 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
2121
2122 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
2123 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
2124 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
2125 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
2126 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
2127 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
2128 LLVMBuildBr(g->builder, loop_block);
2129
2130 LLVMPositionBuilderAtEnd(g->builder, loop_block);
2131 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
2132 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
2133 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
2134 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
2135 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
2136 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
2137 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
2138 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
2139 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
2140 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
2141
2142 LLVMPositionBuilderAtEnd(g->builder, return_block);
2143 LLVMBuildRetVoid(g->builder);
2144
2145 LLVMPositionBuilderAtEnd(g->builder, continue_block);
2146 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
2147 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
2148 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
2149 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
2150 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
2151 LLVMBuildBr(g->builder, loop_block);
2152
2153 LLVMPositionBuilderAtEnd(g->builder, prev_block);
2154 if (!g->strip_debug_symbols) {
2155 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
2156 }
2157
2158 g->merge_err_ret_traces_fn_val = fn_val;
2159 return fn_val;
2160
2161}
2029static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,2162static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
2030 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)2163 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
2031{2164{
2032 assert(g->have_err_ret_tracing);2165 assert(g->have_err_ret_tracing);
20332166
2034 LLVMValueRef return_err_fn = get_return_err_fn(g);2167 LLVMValueRef return_err_fn = get_return_err_fn(g);
2035 LLVMValueRef args[] = {2168 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope);
2036 get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope),2169 ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1,
2037 };
2038 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
2039 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");2170 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2040 return call_instruction;2171
2172 if (fn_is_async(g->cur_fn) && g->cur_fn->calls_or_awaits_errorable_fn &&
2173 codegen_fn_has_err_ret_tracing_arg(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type))
2174 {
2175 LLVMValueRef dest_trace_ptr = LLVMBuildLoad(g->builder, g->cur_err_ret_trace_val_arg, "");
2176 LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val };
2177 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
2178 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2179 }
2180
2181 return nullptr;
2041}2182}
20422183
2043static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, ResumeId resume_id, PanicMsgId msg_id,2184static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, ResumeId resume_id, PanicMsgId msg_id,
test/runtime_safety.zig+11-5
...@@ -544,23 +544,29 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -544,23 +544,29 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
544 \\ std.os.exit(126);544 \\ std.os.exit(126);
545 \\}545 \\}
546 \\546 \\
547 \\var failing_frame: @Frame(failing) = undefined;
548 \\
547 \\pub fn main() void {549 \\pub fn main() void {
548 \\ const p = nonFailing();550 \\ const p = nonFailing();
549 \\ resume p;551 \\ resume p;
550 \\ const p2 = async<std.debug.global_allocator> printTrace(p) catch unreachable;552 \\ const p2 = async printTrace(p);
551 \\ cancel p2;
552 \\}553 \\}
553 \\554 \\
554 \\fn nonFailing() promise->anyerror!void {555 \\fn nonFailing() anyframe->anyerror!void {
555 \\ return async<std.debug.global_allocator> failing() catch unreachable;556 \\ failing_frame = async failing();
557 \\ return &failing_frame;
556 \\}558 \\}
557 \\559 \\
558 \\async fn failing() anyerror!void {560 \\async fn failing() anyerror!void {
559 \\ suspend;561 \\ suspend;
562 \\ return second();
563 \\}
564 \\
565 \\async fn second() anyerror!void {
560 \\ return error.Fail;566 \\ return error.Fail;
561 \\}567 \\}
562 \\568 \\
563 \\async fn printTrace(p: promise->anyerror!void) void {569 \\async fn printTrace(p: anyframe->anyerror!void) void {
564 \\ (await p) catch unreachable;570 \\ (await p) catch unreachable;
565 \\}571 \\}
566 );572 );