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 {
17151715 PanicMsgIdFrameTooSmall,
17161716 PanicMsgIdResumedFnPendingAwait,
17171717 PanicMsgIdBadNoAsyncCall,
1718 PanicMsgIdResumeNotSuspendedFn,
17181719
17191720 PanicMsgIdCount,
17201721};
......@@ -1886,6 +1887,7 @@ struct CodeGen {
18861887 size_t cur_resume_block_count;
18871888 LLVMValueRef cur_err_ret_trace_val_arg;
18881889 LLVMValueRef cur_err_ret_trace_val_stack;
1890 LLVMValueRef cur_bad_not_suspended_index;
18891891 LLVMValueRef memcpy_fn_val;
18901892 LLVMValueRef memset_fn_val;
18911893 LLVMValueRef trap_fn_val;
src/codegen.cpp+24
......@@ -933,6 +933,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
933933 return buf_create_from_str("resumed an async function which can only be awaited");
934934 case PanicMsgIdBadNoAsyncCall:
935935 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");
936938 }
937939 zig_unreachable();
938940}
......@@ -2234,6 +2236,12 @@ static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, Resume
22342236 LLVMBasicBlockRef end_bb)
22352237{
22362238 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
22372245 LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");
22382246 if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume");
22392247 LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),
......@@ -5764,6 +5772,9 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl
57645772 LLVMBuildRetVoid(g->builder);
57655773
57665774 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 }
57675778 render_async_var_decls(g, instruction->base.scope);
57685779 return nullptr;
57695780}
......@@ -7542,7 +7553,20 @@ static void do_code_gen(CodeGen *g) {
75427553 IrBasicBlock *entry_block = executable->basic_block_list.at(0);
75437554 LLVMAddCase(switch_instr, zero, entry_block->llvm_block);
75447555 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
75457568 LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block);
7569 LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr);
75467570 if (trace_field_index_stack != UINT32_MAX) {
75477571 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {
75487572 LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
test/runtime_safety.zig+48
......@@ -1,6 +1,54 @@
11const tests = @import("tests.zig");
22
33pub 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
452 cases.addRuntimeSafety("noasync function call, callee suspends",
553 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
654 \\ @import("std").os.exit(126);