authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-10-22 23:43:27-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-10-22 23:43:27-04:00
loge98e5dda52d8bcaa2e59861bbbd500b81edfde2d
tree50446ef28111840f0fe92b5a7ea2851af9fb08c0
parent1dcf540426103e762925f3365898d65b1724fdf1
signaturelock-open Commit is signed but in an unrecognized format.

implement safety for resuming non-suspended function

closes #3469

3 files changed, 74 insertions(+), 0 deletions(-)

src/all_types.hpp+2
...@@ -1715,6 +1715,7 @@ enum PanicMsgId {...@@ -1715,6 +1715,7 @@ enum PanicMsgId {
1715 PanicMsgIdFrameTooSmall,1715 PanicMsgIdFrameTooSmall,
1716 PanicMsgIdResumedFnPendingAwait,1716 PanicMsgIdResumedFnPendingAwait,
1717 PanicMsgIdBadNoAsyncCall,1717 PanicMsgIdBadNoAsyncCall,
1718 PanicMsgIdResumeNotSuspendedFn,
17181719
1719 PanicMsgIdCount,1720 PanicMsgIdCount,
1720};1721};
...@@ -1886,6 +1887,7 @@ struct CodeGen {...@@ -1886,6 +1887,7 @@ struct CodeGen {
1886 size_t cur_resume_block_count;1887 size_t cur_resume_block_count;
1887 LLVMValueRef cur_err_ret_trace_val_arg;1888 LLVMValueRef cur_err_ret_trace_val_arg;
1888 LLVMValueRef cur_err_ret_trace_val_stack;1889 LLVMValueRef cur_err_ret_trace_val_stack;
1890 LLVMValueRef cur_bad_not_suspended_index;
1889 LLVMValueRef memcpy_fn_val;1891 LLVMValueRef memcpy_fn_val;
1890 LLVMValueRef memset_fn_val;1892 LLVMValueRef memset_fn_val;
1891 LLVMValueRef trap_fn_val;1893 LLVMValueRef trap_fn_val;
src/codegen.cpp+24
...@@ -933,6 +933,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -933,6 +933,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
933 return buf_create_from_str("resumed an async function which can only be awaited");933 return buf_create_from_str("resumed an async function which can only be awaited");
934 case PanicMsgIdBadNoAsyncCall:934 case PanicMsgIdBadNoAsyncCall:
935 return buf_create_from_str("async function called with noasync suspended");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 zig_unreachable();939 zig_unreachable();
938}940}
...@@ -2234,6 +2236,12 @@ static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, Resume...@@ -2234,6 +2236,12 @@ static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, Resume
2234 LLVMBasicBlockRef end_bb)2236 LLVMBasicBlockRef end_bb)
2235{2237{
2236 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;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 LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");2245 LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");
2238 if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume");2246 if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume");
2239 LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),2247 LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),
...@@ -5764,6 +5772,9 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl...@@ -5764,6 +5772,9 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl
5764 LLVMBuildRetVoid(g->builder);5772 LLVMBuildRetVoid(g->builder);
57655773
5766 LLVMPositionBuilderAtEnd(g->builder, instruction->begin->resume_bb);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 render_async_var_decls(g, instruction->base.scope);5778 render_async_var_decls(g, instruction->base.scope);
5768 return nullptr;5779 return nullptr;
5769}5780}
...@@ -7542,7 +7553,20 @@ static void do_code_gen(CodeGen *g) {...@@ -7542,7 +7553,20 @@ static void do_code_gen(CodeGen *g) {
7542 IrBasicBlock *entry_block = executable->basic_block_list.at(0);7553 IrBasicBlock *entry_block = executable->basic_block_list.at(0);
7543 LLVMAddCase(switch_instr, zero, entry_block->llvm_block);7554 LLVMAddCase(switch_instr, zero, entry_block->llvm_block);
7544 g->cur_resume_block_count += 1;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 LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block);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 if (trace_field_index_stack != UINT32_MAX) {7570 if (trace_field_index_stack != UINT32_MAX) {
7547 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {7571 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {
7548 LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,7572 LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
test/runtime_safety.zig+48
...@@ -1,6 +1,54 @@...@@ -1,6 +1,54 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompareOutputContext) void {3pub 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 cases.addRuntimeSafety("noasync function call, callee suspends",52 cases.addRuntimeSafety("noasync function call, callee suspends",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {53 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);54 \\ @import("std").os.exit(126);