authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-27 18:45:21-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-27 18:45:21-04:00
log2fa588e81d60cfe319446bd0483c6bf296f40c40
treee1cf362f872de63e4c14cd869c1a8549ff7e2519
parent19961c50e4db10fc4ada428928a7f5d1a2966da6

fix coroutine accessing freed memory

closes #1164

3 files changed, 47 insertions(+), 13 deletions(-)

src/analyze.cpp+1-1
......@@ -5583,7 +5583,7 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeT
55835583 return;
55845584 }
55855585 case ConstPtrSpecialHardCodedAddr:
5586 buf_appendf(buf, "(*%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name),
5586 buf_appendf(buf, "(%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->name),
55875587 const_val->data.x_ptr.data.hard_coded_addr.addr);
55885588 return;
55895589 case ConstPtrSpecialDiscard:
src/ir.cpp+14-3
......@@ -7112,6 +7112,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
71127112 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
71137113 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
71147114 }
7115 // Before we destroy the coroutine frame, we need to load the target promise into
7116 // a register or local variable which does not get spilled into the frame,
7117 // otherwise llvm tries to access memory inside the destroyed frame.
7118 IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
7119 irb->exec->await_handle_var_ptr, false);
7120 IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
71157121 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
71167122
71177123 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
......@@ -7126,6 +7132,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
71267132 incoming_values[1] = const_bool_true;
71277133 IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
71287134
7135 IrBasicBlock **merge_incoming_blocks = allocate<IrBasicBlock *>(2);
7136 IrInstruction **merge_incoming_values = allocate<IrInstruction *>(2);
7137 merge_incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
7138 merge_incoming_values[0] = ir_build_const_undefined(irb, scope, node);
7139 merge_incoming_blocks[1] = irb->exec->coro_normal_final;
7140 merge_incoming_values[1] = await_handle_in_block;
7141 IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values);
7142
71297143 Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME);
71307144 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
71317145 ImplicitAllocatorIdLocalVar);
......@@ -7152,9 +7166,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
71527166 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
71537167
71547168 ir_set_cursor_at_end_and_append_block(irb, resume_block);
7155 IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
7156 irb->exec->await_handle_var_ptr, false);
7157 IrInstruction *awaiter_handle = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
71587169 ir_build_coro_resume(irb, scope, node, awaiter_handle);
71597170 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);
71607171 }
test/cases/coroutines.zig+32-9
......@@ -5,7 +5,10 @@ const assert = std.debug.assert;
55var x: i32 = 1;
66
77test "create a coroutine and cancel it" {
8 const p = try async<std.debug.global_allocator> simpleAsyncFn();
8 var da = std.heap.DirectAllocator.init();
9 defer da.deinit();
10
11 const p = try async<&da.allocator> simpleAsyncFn();
912 comptime assert(@typeOf(p) == promise->void);
1013 cancel p;
1114 assert(x == 2);
......@@ -17,8 +20,11 @@ async fn simpleAsyncFn() void {
1720}
1821
1922test "coroutine suspend, resume, cancel" {
23 var da = std.heap.DirectAllocator.init();
24 defer da.deinit();
25
2026 seq('a');
21 const p = try async<std.debug.global_allocator> testAsyncSeq();
27 const p = try async<&da.allocator> testAsyncSeq();
2228 seq('c');
2329 resume p;
2430 seq('f');
......@@ -43,7 +49,10 @@ fn seq(c: u8) void {
4349}
4450
4551test "coroutine suspend with block" {
46 const p = try async<std.debug.global_allocator> testSuspendBlock();
52 var da = std.heap.DirectAllocator.init();
53 defer da.deinit();
54
55 const p = try async<&da.allocator> testSuspendBlock();
4756 std.debug.assert(!result);
4857 resume a_promise;
4958 std.debug.assert(result);
......@@ -64,8 +73,11 @@ var await_a_promise: promise = undefined;
6473var await_final_result: i32 = 0;
6574
6675test "coroutine await" {
76 var da = std.heap.DirectAllocator.init();
77 defer da.deinit();
78
6779 await_seq('a');
68 const p = async<std.debug.global_allocator> await_amain() catch unreachable;
80 const p = async<&da.allocator> await_amain() catch unreachable;
6981 await_seq('f');
7082 resume await_a_promise;
7183 await_seq('i');
......@@ -100,8 +112,11 @@ fn await_seq(c: u8) void {
100112var early_final_result: i32 = 0;
101113
102114test "coroutine await early return" {
115 var da = std.heap.DirectAllocator.init();
116 defer da.deinit();
117
103118 early_seq('a');
104 const p = async<std.debug.global_allocator> early_amain() catch unreachable;
119 const p = async<&da.allocator> early_amain() catch unreachable;
105120 early_seq('f');
106121 assert(early_final_result == 1234);
107122 assert(std.mem.eql(u8, early_points, "abcdef"));
......@@ -146,7 +161,9 @@ test "async function with dot syntax" {
146161 suspend;
147162 }
148163 };
149 const p = try async<std.debug.global_allocator> S.foo();
164 var da = std.heap.DirectAllocator.init();
165 defer da.deinit();
166 const p = try async<&da.allocator> S.foo();
150167 cancel p;
151168 assert(S.y == 2);
152169}
......@@ -157,7 +174,9 @@ test "async fn pointer in a struct field" {
157174 bar: async<*std.mem.Allocator> fn (*i32) void,
158175 };
159176 var foo = Foo{ .bar = simpleAsyncFn2 };
160 const p = (async<std.debug.global_allocator> foo.bar(&data)) catch unreachable;
177 var da = std.heap.DirectAllocator.init();
178 defer da.deinit();
179 const p = (async<&da.allocator> foo.bar(&data)) catch unreachable;
161180 assert(data == 2);
162181 cancel p;
163182 assert(data == 4);
......@@ -169,7 +188,9 @@ async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
169188}
170189
171190test "async fn with inferred error set" {
172 const p = (async<std.debug.global_allocator> failing()) catch unreachable;
191 var da = std.heap.DirectAllocator.init();
192 defer da.deinit();
193 const p = (async<&da.allocator> failing()) catch unreachable;
173194 resume p;
174195 cancel p;
175196}
......@@ -181,7 +202,9 @@ async fn failing() !void {
181202test "error return trace across suspend points - early return" {
182203 const p = nonFailing();
183204 resume p;
184 const p2 = try async<std.debug.global_allocator> printTrace(p);
205 var da = std.heap.DirectAllocator.init();
206 defer da.deinit();
207 const p2 = try async<&da.allocator> printTrace(p);
185208 cancel p2;
186209}
187210