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
43844384 arg_calc = arg_calc_start;
43854385 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
43864386 CalcLLVMFieldIndex prev = arg_calc;
4387 // Use the declared argument type and not the value one to be
4388 // consistent with the assignment operation below.
43874389 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));
43894391 if (arg_calc.field_index - prev.field_index > 1) {
43904392 // Padding field
43914393 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" {
15591559 resume @ptrCast(anyframe->bool, @alignCast(@alignOf(@Frame(S.foo)), S.x));
15601560 expect(nosuspend await frame);
15611561}
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}