| author | |
| committer | |
| log | e98e5dda52d8bcaa2e59861bbbd500b81edfde2d |
| tree | 50446ef28111840f0fe92b5a7ea2851af9fb08c0 |
| parent | 1dcf540426103e762925f3365898d65b1724fdf1 |
| signature |
closes #34693 files changed, 74 insertions(+), 0 deletions(-)
src/all_types.hpp+2| ... | ... | @@ -1715,6 +1715,7 @@ enum PanicMsgId { |
| 1715 | 1715 | PanicMsgIdFrameTooSmall, |
| 1716 | 1716 | PanicMsgIdResumedFnPendingAwait, |
| 1717 | 1717 | PanicMsgIdBadNoAsyncCall, |
| 1718 | PanicMsgIdResumeNotSuspendedFn, | |
| 1718 | 1719 | |
| 1719 | 1720 | PanicMsgIdCount, |
| 1720 | 1721 | }; |
| ... | ... | @@ -1886,6 +1887,7 @@ struct CodeGen { |
| 1886 | 1887 | size_t cur_resume_block_count; |
| 1887 | 1888 | LLVMValueRef cur_err_ret_trace_val_arg; |
| 1888 | 1889 | LLVMValueRef cur_err_ret_trace_val_stack; |
| 1890 | LLVMValueRef cur_bad_not_suspended_index; | |
| 1889 | 1891 | LLVMValueRef memcpy_fn_val; |
| 1890 | 1892 | LLVMValueRef memset_fn_val; |
| 1891 | 1893 | LLVMValueRef trap_fn_val; |
src/codegen.cpp+24| ... | ... | @@ -933,6 +933,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { |
| 933 | 933 | return buf_create_from_str("resumed an async function which can only be awaited"); |
| 934 | 934 | case PanicMsgIdBadNoAsyncCall: |
| 935 | 935 | return buf_create_from_str("async function called with noasync suspended"); |
| 936 | case PanicMsgIdResumeNotSuspendedFn: | |
| 937 | return buf_create_from_str("resumed a non-suspended function"); | |
| 936 | 938 | } |
| 937 | 939 | zig_unreachable(); |
| 938 | 940 | } |
| ... | ... | @@ -2234,6 +2236,12 @@ static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, Resume |
| 2234 | 2236 | LLVMBasicBlockRef end_bb) |
| 2235 | 2237 | { |
| 2236 | 2238 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 2239 | ||
| 2240 | if (ir_want_runtime_safety(g, source_instr)) { | |
| 2241 | // Write a value to the resume index which indicates the function was resumed while not suspended. | |
| 2242 | LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); | |
| 2243 | } | |
| 2244 | ||
| 2237 | 2245 | LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); |
| 2238 | 2246 | if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume"); |
| 2239 | 2247 | LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), |
| ... | ... | @@ -5764,6 +5772,9 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl |
| 5764 | 5772 | LLVMBuildRetVoid(g->builder); |
| 5765 | 5773 | |
| 5766 | 5774 | LLVMPositionBuilderAtEnd(g->builder, instruction->begin->resume_bb); |
| 5775 | if (ir_want_runtime_safety(g, &instruction->base)) { | |
| 5776 | LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); | |
| 5777 | } | |
| 5767 | 5778 | render_async_var_decls(g, instruction->base.scope); |
| 5768 | 5779 | return nullptr; |
| 5769 | 5780 | } |
| ... | ... | @@ -7542,7 +7553,20 @@ static void do_code_gen(CodeGen *g) { |
| 7542 | 7553 | IrBasicBlock *entry_block = executable->basic_block_list.at(0); |
| 7543 | 7554 | LLVMAddCase(switch_instr, zero, entry_block->llvm_block); |
| 7544 | 7555 | g->cur_resume_block_count += 1; |
| 7556 | ||
| 7557 | { | |
| 7558 | LLVMBasicBlockRef bad_not_suspended_bb = LLVMAppendBasicBlock(g->cur_fn_val, "NotSuspended"); | |
| 7559 | size_t new_block_index = g->cur_resume_block_count; | |
| 7560 | g->cur_resume_block_count += 1; | |
| 7561 | g->cur_bad_not_suspended_index = LLVMConstInt(usize_type_ref, new_block_index, false); | |
| 7562 | LLVMAddCase(g->cur_async_switch_instr, g->cur_bad_not_suspended_index, bad_not_suspended_bb); | |
| 7563 | ||
| 7564 | LLVMPositionBuilderAtEnd(g->builder, bad_not_suspended_bb); | |
| 7565 | gen_assertion_scope(g, PanicMsgIdResumeNotSuspendedFn, fn_table_entry->child_scope); | |
| 7566 | } | |
| 7567 | ||
| 7545 | 7568 | LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block); |
| 7569 | LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); | |
| 7546 | 7570 | if (trace_field_index_stack != UINT32_MAX) { |
| 7547 | 7571 | if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { |
| 7548 | 7572 | LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, |
test/runtime_safety.zig+48| ... | ... | @@ -1,6 +1,54 @@ |
| 1 | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 3 | pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 4 | cases.addRuntimeSafety("resuming a non-suspended function which never been suspended", | |
| 5 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | |
| 6 | \\ @import("std").os.exit(126); | |
| 7 | \\} | |
| 8 | \\fn foo() void { | |
| 9 | \\ var f = async bar(@frame()); | |
| 10 | \\ @import("std").os.exit(0); | |
| 11 | \\} | |
| 12 | \\ | |
| 13 | \\fn bar(frame: anyframe) void { | |
| 14 | \\ suspend { | |
| 15 | \\ resume frame; | |
| 16 | \\ } | |
| 17 | \\ @import("std").os.exit(0); | |
| 18 | \\} | |
| 19 | \\ | |
| 20 | \\pub fn main() void { | |
| 21 | \\ _ = async foo(); | |
| 22 | \\} | |
| 23 | ); | |
| 24 | ||
| 25 | cases.addRuntimeSafety("resuming a non-suspended function which has been suspended and resumed", | |
| 26 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | |
| 27 | \\ @import("std").os.exit(126); | |
| 28 | \\} | |
| 29 | \\fn foo() void { | |
| 30 | \\ suspend { | |
| 31 | \\ global_frame = @frame(); | |
| 32 | \\ } | |
| 33 | \\ var f = async bar(@frame()); | |
| 34 | \\ @import("std").os.exit(0); | |
| 35 | \\} | |
| 36 | \\ | |
| 37 | \\fn bar(frame: anyframe) void { | |
| 38 | \\ suspend { | |
| 39 | \\ resume frame; | |
| 40 | \\ } | |
| 41 | \\ @import("std").os.exit(0); | |
| 42 | \\} | |
| 43 | \\ | |
| 44 | \\var global_frame: anyframe = undefined; | |
| 45 | \\pub fn main() void { | |
| 46 | \\ _ = async foo(); | |
| 47 | \\ resume global_frame; | |
| 48 | \\ @import("std").os.exit(0); | |
| 49 | \\} | |
| 50 | ); | |
| 51 | ||
| 4 | 52 | cases.addRuntimeSafety("noasync function call, callee suspends", |
| 5 | 53 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { |
| 6 | 54 | \\ @import("std").os.exit(126); |