authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-11-14 15:30:06+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-11-14 15:30:06+01:00
log7ebbc717c01ca46486a6a3447f9152fde7c5166e
treef3e69abd6a5e50c621579261a3aaa55f7ccdf3b0
parentab4b34f75f5762b4bc87ccc49df73ebf0f633c5a

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
...@@ -4384,8 +4384,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn...@@ -4384,8 +4384,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
4384 arg_calc = arg_calc_start;4384 arg_calc = arg_calc_start;
4385 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {4385 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
4386 CalcLLVMFieldIndex prev = arg_calc;4386 CalcLLVMFieldIndex prev = arg_calc;
4387 // Use the declared argument type and not the value one to be
4388 // consistent with the assignment operation below.
4387 calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i));4389 calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i));
4388 field_types[arg_calc.field_index - 1] = LLVMTypeOf(gen_param_values.at(arg_i));4390 field_types[arg_calc.field_index - 1] = get_llvm_type(g, gen_param_types.at(arg_i));
4389 if (arg_calc.field_index - prev.field_index > 1) {4391 if (arg_calc.field_index - prev.field_index > 1) {
4390 // Padding field4392 // Padding field
4391 uint32_t pad_bytes = arg_calc.offset - prev.offset - gen_param_types.at(arg_i)->abi_size;4393 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}