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 {
16801680 PanicMsgIdResumedAnAwaitingFn,
16811681 PanicMsgIdFrameTooSmall,
16821682 PanicMsgIdResumedFnPendingAwait,
1683 PanicMsgIdBadNoAsyncCall,
16831684
16841685 PanicMsgIdCount,
16851686};
src/codegen.cpp+21
......@@ -923,6 +923,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
923923 return buf_create_from_str("frame too small");
924924 case PanicMsgIdResumedFnPendingAwait:
925925 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");
926928 }
927929 zig_unreachable();
928930}
......@@ -4067,6 +4069,25 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
40674069 } else if (instruction->modifier == CallModifierNoAsync && !fn_is_async(g->cur_fn)) {
40684070 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
40704091 ZigType *result_type = instruction->base.value.type;
40714092 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);
40724093 return gen_await_early_return(g, &instruction->base, frame_result_loc,
test/runtime_safety.zig+15
......@@ -1,6 +1,21 @@
11const tests = @import("tests.zig");
22
33pub 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
419 cases.addRuntimeSafety("awaiting twice",
520 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
621 \\ @import("std").os.exit(126);