Commit f1eed99f3d

David Rubin <87927264+Rexicon226@users.noreply.github.com>
2024-08-16 18:41:58
add an error for stack allocations in naked functions (#21082)
closes #72
1 parent 11176d2
Changed files (2)
src
test
src/Sema.zig
@@ -3626,8 +3626,7 @@ fn zirAllocExtended(
     const alignment = if (small.has_align) blk: {
         const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
         extra_index += 1;
-        const alignment = try sema.resolveAlign(block, align_src, align_ref);
-        break :blk alignment;
+        break :blk try sema.resolveAlign(block, align_src, align_ref);
     } else .none;
 
     if (block.is_comptime or small.is_comptime) {
@@ -3652,6 +3651,10 @@ fn zirAllocExtended(
         }
         const target = pt.zcu.getTarget();
         try var_ty.resolveLayout(pt);
+        if (sema.func_is_naked and try sema.typeHasRuntimeBits(var_ty)) {
+            const var_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node });
+            return sema.fail(block, var_src, "local variable in naked function", .{});
+        }
         const ptr_type = try sema.pt.ptrTypeSema(.{
             .child = var_ty.toIntern(),
             .flags = .{
@@ -4087,10 +4090,15 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
 
     const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
     const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
+
     const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
     if (block.is_comptime) {
         return sema.analyzeComptimeAlloc(block, var_ty, .none);
     }
+    if (sema.func_is_naked and try sema.typeHasRuntimeBits(var_ty)) {
+        const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
+        return sema.fail(block, mut_src, "local variable in naked function", .{});
+    }
     const target = pt.zcu.getTarget();
     const ptr_type = try pt.ptrTypeSema(.{
         .child = var_ty.toIntern(),
@@ -4115,6 +4123,10 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
     if (block.is_comptime) {
         return sema.analyzeComptimeAlloc(block, var_ty, .none);
     }
+    if (sema.func_is_naked and try sema.typeHasRuntimeBits(var_ty)) {
+        const var_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
+        return sema.fail(block, var_src, "local variable in naked function", .{});
+    }
     try sema.validateVarType(block, ty_src, var_ty, false);
     const target = pt.zcu.getTarget();
     const ptr_type = try pt.ptrTypeSema(.{
@@ -4248,7 +4260,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
                 // TODO: source location of runtime control flow
                 return sema.fail(block, src, "value with comptime-only type '{}' depends on runtime control flow", .{final_elem_ty.fmt(pt)});
             }
-
+            if (sema.func_is_naked and try sema.typeHasRuntimeBits(final_elem_ty)) {
+                const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
+                return sema.fail(block, mut_src, "local variable in naked function", .{});
+            }
             // Change it to a normal alloc.
             sema.air_instructions.set(@intFromEnum(ptr_inst), .{
                 .tag = .alloc,
test/cases/compile_errors/stack_usage_in_naked_function.zig
@@ -0,0 +1,45 @@
+export fn a() callconv(.Naked) noreturn {
+    var x: u32 = 10;
+    _ = &x;
+
+    const y: u32 = x + 10;
+    _ = y;
+}
+
+export fn b() callconv(.Naked) noreturn {
+    var x = @as(u32, 10);
+    _ = &x;
+
+    const y = x;
+    var z = y;
+    _ = &z;
+}
+
+export fn c() callconv(.Naked) noreturn {
+    const Foo = struct {
+        y: u32,
+    };
+
+    var x: Foo = .{ .y = 10 };
+    _ = &x;
+}
+
+export fn d() callconv(.Naked) noreturn {
+    const Foo = struct {
+        inline fn bar() void {
+            var x: u32 = 10;
+            _ = &x;
+        }
+    };
+
+    Foo.bar();
+}
+
+// error
+// backend=stage2
+//
+// :2:5: error: local variable in naked function
+// :10:5: error: local variable in naked function
+// :23:5: error: local variable in naked function
+// :30:13: error: local variable in naked function
+// :35:12: note: called from here