authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-06 12:50:51-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-06 13:08:44-04:00
log7d303ae861b807c84ca99078b63fe35a69f712d7
tree13153c221bbdf858d0aa97f4cb2265a702e1936c
parent0a3c6dbda92931eba055c2c6447b7a4412408f17
signaturelock-open Commit is signed but in an unrecognized format.

runtime safety for noasync function calls

See #3157

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

src/all_types.hpp+1
...@@ -1680,6 +1680,7 @@ enum PanicMsgId {...@@ -1680,6 +1680,7 @@ enum PanicMsgId {
1680 PanicMsgIdResumedAnAwaitingFn,1680 PanicMsgIdResumedAnAwaitingFn,
1681 PanicMsgIdFrameTooSmall,1681 PanicMsgIdFrameTooSmall,
1682 PanicMsgIdResumedFnPendingAwait,1682 PanicMsgIdResumedFnPendingAwait,
1683 PanicMsgIdBadNoAsyncCall,
16831684
1684 PanicMsgIdCount,1685 PanicMsgIdCount,
1685};1686};
src/codegen.cpp+21
...@@ -923,6 +923,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -923,6 +923,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
923 return buf_create_from_str("frame too small");923 return buf_create_from_str("frame too small");
924 case PanicMsgIdResumedFnPendingAwait:924 case PanicMsgIdResumedFnPendingAwait:
925 return buf_create_from_str("resumed an async function which can only be awaited");925 return buf_create_from_str("resumed an async function which can only be awaited");
926 case PanicMsgIdBadNoAsyncCall:
927 return buf_create_from_str("async function called with noasync suspended");
926 }928 }
927 zig_unreachable();929 zig_unreachable();
928}930}
...@@ -4067,6 +4069,25 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -4067,6 +4069,25 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
4067 } else if (instruction->modifier == CallModifierNoAsync && !fn_is_async(g->cur_fn)) {4069 } else if (instruction->modifier == CallModifierNoAsync && !fn_is_async(g->cur_fn)) {
4068 gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);4070 gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);
40694071
4072 if (ir_want_runtime_safety(g, &instruction->base)) {
4073 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
4074 frame_awaiter_index, "");
4075 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
4076 LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr,
4077 all_ones, LLVMAtomicOrderingRelease);
4078 LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, prev_val, all_ones, "");
4079
4080 LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoAsyncPanic");
4081 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoAsyncOk");
4082 LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block);
4083
4084 // The async function suspended, but this noasync call asserted it wouldn't.
4085 LLVMPositionBuilderAtEnd(g->builder, bad_block);
4086 gen_safety_crash(g, PanicMsgIdBadNoAsyncCall);
4087
4088 LLVMPositionBuilderAtEnd(g->builder, ok_block);
4089 }
4090
4070 ZigType *result_type = instruction->base.value.type;4091 ZigType *result_type = instruction->base.value.type;
4071 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);4092 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);
4072 return gen_await_early_return(g, &instruction->base, frame_result_loc,4093 return gen_await_early_return(g, &instruction->base, frame_result_loc,
test/runtime_safety.zig+15
...@@ -1,6 +1,21 @@...@@ -1,6 +1,21 @@
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("noasync function call, callee suspends",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\pub fn main() void {
9 \\ _ = noasync add(101, 100);
10 \\}
11 \\fn add(a: i32, b: i32) i32 {
12 \\ if (a > 100) {
13 \\ suspend;
14 \\ }
15 \\ return a + b;
16 \\}
17 );
18
4 cases.addRuntimeSafety("awaiting twice",19 cases.addRuntimeSafety("awaiting twice",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {20 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);21 \\ @import("std").os.exit(126);