Commit 6624f9cd5c

LemonBoy <thatlemon@gmail.com>
2020-11-14 15:30:06
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
1 parent 7d0c461
Changed files (2)
src
test
stage1
behavior
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;
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,
+    });
+}