From 6624f9cd5c2d747224990fb9ba3e2b830a68f3e4 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 14 Nov 2020 15:30:06 +0100 Subject: [PATCH] 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 --- src/stage1/codegen.cpp | 4 +++- test/stage1/behavior/async_fn.zig | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index b9c068d7f7da2299a41a6b9bae52e48a43ec4280..53b9385e27dabcc1b1cd8d7872175225df4216fd 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -4411,8 +4411,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn arg_calc = arg_calc_start; for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) { CalcLLVMFieldIndex prev = arg_calc; + // Use the declared argument type and not the value one to be + // consistent with the assignment operation below. calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i)); - field_types[arg_calc.field_index - 1] = LLVMTypeOf(gen_param_values.at(arg_i)); + field_types[arg_calc.field_index - 1] = get_llvm_type(g, gen_param_types.at(arg_i)); if (arg_calc.field_index - prev.field_index > 1) { // Padding field uint32_t pad_bytes = arg_calc.offset - prev.offset - gen_param_types.at(arg_i)->abi_size; diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index e2cececf69e8d0a14b07220c3bd3fac70ad4a125..d148d84064dd3ea3a219cf7024cccb8a6c8df9d4 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1559,3 +1559,33 @@ test "avoid forcing frame alignment resolution implicit cast to *c_void" { resume @ptrCast(anyframe->bool, @alignCast(@alignOf(@Frame(S.foo)), S.x)); expect(nosuspend await frame); } + +test "@asyncCall with pass-by-value arguments" { + const F0: u64 = 0xbeefbeefbeefbeef; + const F1: u64 = 0xf00df00df00df00d; + const F2: u64 = 0xcafecafecafecafe; + + const S = struct { + pub const ST = struct { f0: usize, f1: usize }; + pub const AT = [5]u8; + + pub fn f(_fill0: u64, s: ST, _fill1: u64, a: AT, _fill2: u64) callconv(.Async) void { + // Check that the array and struct arguments passed by value don't + // end up overflowing the adjacent fields in the frame structure. + expectEqual(F0, _fill0); + expectEqual(F1, _fill1); + expectEqual(F2, _fill2); + } + }; + + var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined; + // The function pointer must not be comptime-known. + var t = S.f; + var frame_ptr = @asyncCall(&buffer, {}, t, .{ + F0, + .{ .f0 = 1, .f1 = 2 }, + F1, + [_]u8{ 1, 2, 3, 4, 5 }, + F2, + }); +} -- 2.54.0