authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-11-14 15:30:06+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-16 11:37:49-07:00
log6624f9cd5c2d747224990fb9ba3e2b830a68f3e4
tree83df668aaca89947fb00b52486873bdfd33b6a0f
parent7d0c461b77890847899548cc69a701bcb0a3a6a6

stage1: Fix generation of pass-by-value args in async fns

The mismatch between the argument slot type in the frame structure and the one used in the store operation made the generated code write garbage over the nearby fields. Fixes #7104

2 files changed, 33 insertions(+), 1 deletions(-)

src/stage1/codegen.cpp+3-1
...@@ -4411,8 +4411,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn...@@ -4411,8 +4411,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
4411 arg_calc = arg_calc_start;4411 arg_calc = arg_calc_start;
4412 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {4412 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
4413 CalcLLVMFieldIndex prev = arg_calc;4413 CalcLLVMFieldIndex prev = arg_calc;
4414 // Use the declared argument type and not the value one to be
4415 // consistent with the assignment operation below.
4414 calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i));4416 calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i));
4415 field_types[arg_calc.field_index - 1] = LLVMTypeOf(gen_param_values.at(arg_i));4417 field_types[arg_calc.field_index - 1] = get_llvm_type(g, gen_param_types.at(arg_i));
4416 if (arg_calc.field_index - prev.field_index > 1) {4418 if (arg_calc.field_index - prev.field_index > 1) {
4417 // Padding field4419 // Padding field
4418 uint32_t pad_bytes = arg_calc.offset - prev.offset - gen_param_types.at(arg_i)->abi_size;4420 uint32_t pad_bytes = arg_calc.offset - prev.offset - gen_param_types.at(arg_i)->abi_size;
test/stage1/behavior/async_fn.zig+30
...@@ -1559,3 +1559,33 @@ test "avoid forcing frame alignment resolution implicit cast to *c_void" {...@@ -1559,3 +1559,33 @@ test "avoid forcing frame alignment resolution implicit cast to *c_void" {
1559 resume @ptrCast(anyframe->bool, @alignCast(@alignOf(@Frame(S.foo)), S.x));1559 resume @ptrCast(anyframe->bool, @alignCast(@alignOf(@Frame(S.foo)), S.x));
1560 expect(nosuspend await frame);1560 expect(nosuspend await frame);
1561}1561}
1562
1563test "@asyncCall with pass-by-value arguments" {
1564 const F0: u64 = 0xbeefbeefbeefbeef;
1565 const F1: u64 = 0xf00df00df00df00d;
1566 const F2: u64 = 0xcafecafecafecafe;
1567
1568 const S = struct {
1569 pub const ST = struct { f0: usize, f1: usize };
1570 pub const AT = [5]u8;
1571
1572 pub fn f(_fill0: u64, s: ST, _fill1: u64, a: AT, _fill2: u64) callconv(.Async) void {
1573 // Check that the array and struct arguments passed by value don't
1574 // end up overflowing the adjacent fields in the frame structure.
1575 expectEqual(F0, _fill0);
1576 expectEqual(F1, _fill1);
1577 expectEqual(F2, _fill2);
1578 }
1579 };
1580
1581 var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined;
1582 // The function pointer must not be comptime-known.
1583 var t = S.f;
1584 var frame_ptr = @asyncCall(&buffer, {}, t, .{
1585 F0,
1586 .{ .f0 = 1, .f1 = 2 },
1587 F1,
1588 [_]u8{ 1, 2, 3, 4, 5 },
1589 F2,
1590 });
1591}