| author | |
| committer | |
| log | 6624f9cd5c2d747224990fb9ba3e2b830a68f3e4 |
| tree | 83df668aaca89947fb00b52486873bdfd33b6a0f |
| parent | 7d0c461b77890847899548cc69a701bcb0a3a6a6 |
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 #71042 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 field | 4419 | // 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 | |||
| 1563 | test "@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 | } |