From c3d96b7edd68fd4eeb0f65db211b67c05c63fa30 Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Thu, 15 Jun 2023 07:19:56 -0400 Subject: [PATCH] Sema: catch invalid asm input operands Fixes #7843 --- src/Module.zig | 20 ++++++ src/Sema.zig | 30 +++++++++ .../compile_errors/bad_asm_input_operands.zig | 66 +++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 test/cases/compile_errors/bad_asm_input_operands.zig diff --git a/src/Module.zig b/src/Module.zig index e1db07ab7269..080ec0511a60 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -2385,6 +2385,14 @@ pub const SrcLoc = struct { const node_datas = tree.nodes.items(.data); return nodeToSpan(tree, node_datas[asm_output].lhs); }, + .asm_input_op => |asm_input_op| { + const tree = try src_loc.file_scope.getTree(gpa); + const node = src_loc.declRelativeToNodeIndex(asm_input_op.asm_node_offset); + const full = tree.fullAsm(node).?; + const asm_input = full.inputs[asm_input_op.input_index]; + const node_datas = tree.nodes.items(.data); + return nodeToSpan(tree, node_datas[asm_input].lhs); + }, .node_offset_if_cond => |node_off| { const tree = try src_loc.file_scope.getTree(gpa); @@ -2988,6 +2996,17 @@ pub const LazySrcLoc = union(enum) { /// to the return type expression. /// The Decl is determined contextually. node_offset_asm_ret_ty: i32, + /// The source location points to the operand of an input of an inline assembly + /// expression, found by taking this AST node index offset from the containing + /// Decl AST node, which points to inline assembly AST node. Next, navigate + /// to the input operand expression. + /// The Decl is determined contextually. + asm_input_op: struct { + /// Points to the asm AST node. + asm_node_offset: i32, + /// Picks one of the inputs from the asm. + input_index: u32, + }, /// The source location points to the condition expression of an if /// expression, found by taking this AST node index offset from the containing /// Decl AST node, which points to an if expression AST node. Next, navigate @@ -3196,6 +3215,7 @@ pub const LazySrcLoc = union(enum) { .node_offset_deref_ptr, .node_offset_asm_source, .node_offset_asm_ret_ty, + .asm_input_op, .node_offset_if_cond, .node_offset_bin_op, .node_offset_bin_lhs, diff --git a/src/Sema.zig b/src/Sema.zig index 1bbd253b927e..213833c70e2d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -15833,6 +15833,36 @@ fn zirAsm( .ComptimeInt => arg.* = try sema.coerce(block, Type.usize, uncasted_arg, src), .ComptimeFloat => arg.* = try sema.coerce(block, Type.f64, uncasted_arg, src), else => { + const input_op_src: LazySrcLoc = .{ + .asm_input_op = .{ + .asm_node_offset = extra.data.src_node, + .input_index = @intCast(arg_i), + }, + }; + if (uncasted_arg_ty.comptimeOnly(mod)) { + return sema.fail( + block, + input_op_src, + "type '{}' is comptime-only and cannot be used for an asm input operand", + .{uncasted_arg_ty.fmt(mod)}, + ); + } + if (!uncasted_arg_ty.hasRuntimeBits(mod)) { + return sema.fail( + block, + input_op_src, + "type '{}' does not have runtime bits and cannot be used for an asm input operand", + .{uncasted_arg_ty.fmt(mod)}, + ); + } + if (!uncasted_arg_ty.hasWellDefinedLayout(mod)) { + return sema.fail( + block, + input_op_src, + "type '{}' does not have a well-defined memory layout and cannot be used for an asm input operand", + .{uncasted_arg_ty.fmt(mod)}, + ); + } arg.* = uncasted_arg; try sema.queueFullTypeResolution(uncasted_arg_ty); }, diff --git a/test/cases/compile_errors/bad_asm_input_operands.zig b/test/cases/compile_errors/bad_asm_input_operands.zig new file mode 100644 index 000000000000..73c81981a0e0 --- /dev/null +++ b/test/cases/compile_errors/bad_asm_input_operands.zig @@ -0,0 +1,66 @@ +export fn a() void { + asm volatile ("" + : + : [_] "{al}" (u8), + ); +} +export fn b() void { + asm volatile ("" + : + : [_] "{a}" (0), + [_] "{x}" (&&void), + ); +} +export fn c() void { + asm volatile ("" + : + : [_] "{x}" (1), + [_] "{x}" (struct {}{}), + ); +} +export fn d() void { + asm volatile ("" + : + : [_] "{x}" (((packed struct { x: u8 }){ .x = 1 })), + [_] "{x}" (extern struct { x: u8 }{ .x = 1 }), + [_] "{x}" (struct { x: u8 }{ .x = 1 }), + ); +} +export fn e() void { + asm volatile ("" + : + : [_] "{x}" (@Vector(3, u8){ 1, 2, 3 }), + [_] "{x}" ([2]*const type{ &u8, &u8 }), + ); +} +export fn f() void { + asm volatile ("" + : + : [_] "{x}" (undefined), + ); +} +export fn g() void { + asm volatile ("" + : + : [_] "{x}" ({}), + ); +} +export fn h() void { + asm volatile ("" + : + : [_] "{x}" (@as([]const u8, "hello")), + ); +} + +// error +// backend=stage2 +// target=native +// +// :4:23: error: type 'type' is comptime-only and cannot be used for an asm input operand +// :11:22: error: type '*const *const type' is comptime-only and cannot be used for an asm input operand +// :18:31: error: type 'tmp.c__struct_1046' does not have runtime bits and cannot be used for an asm input operand +// :26:38: error: type 'tmp.d__struct_1049' does not have well-defined memory layout and cannot be used for an asm input operand +// :33:36: error: type '[2]*const type' is comptime-only and cannot be used for an asm input operand +// :39:22: error: type '@TypeOf(undefined)' is comptime-only and cannot be used for an asm input operand +// :45:22: error: type 'void' does not have runtime bits and cannot be used for an asm input operand +// :51:22: error: type '[]const u8' does not have well-defined memory layout and cannot be used for an asm input operand