authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-08-16 09:41:58-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-16 09:41:58-07:00
logf1eed99f3d2d355054c6cf36d6f332d83b2ec595
tree286d1eb20b6d52ad1a5d75569cc45407a62c0064
parent11176d22f82861b4b6967b77f753414f214bc632
signaturebadge-check Signed by PGP key B5690EEEBB952194

add an error for stack allocations in naked functions (#21082)

closes #72

2 files changed, 63 insertions(+), 3 deletions(-)

src/Sema.zig+18-3
...@@ -3626,8 +3626,7 @@ fn zirAllocExtended(...@@ -3626,8 +3626,7 @@ fn zirAllocExtended(
3626 const alignment = if (small.has_align) blk: {3626 const alignment = if (small.has_align) blk: {
3627 const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);3627 const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
3628 extra_index += 1;3628 extra_index += 1;
3629 const alignment = try sema.resolveAlign(block, align_src, align_ref);3629 break :blk try sema.resolveAlign(block, align_src, align_ref);
3630 break :blk alignment;
3631 } else .none;3630 } else .none;
36323631
3633 if (block.is_comptime or small.is_comptime) {3632 if (block.is_comptime or small.is_comptime) {
...@@ -3652,6 +3651,10 @@ fn zirAllocExtended(...@@ -3652,6 +3651,10 @@ fn zirAllocExtended(
3652 }3651 }
3653 const target = pt.zcu.getTarget();3652 const target = pt.zcu.getTarget();
3654 try var_ty.resolveLayout(pt);3653 try var_ty.resolveLayout(pt);
3654 if (sema.func_is_naked and try sema.typeHasRuntimeBits(var_ty)) {
3655 const var_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node });
3656 return sema.fail(block, var_src, "local variable in naked function", .{});
3657 }
3655 const ptr_type = try sema.pt.ptrTypeSema(.{3658 const ptr_type = try sema.pt.ptrTypeSema(.{
3656 .child = var_ty.toIntern(),3659 .child = var_ty.toIntern(),
3657 .flags = .{3660 .flags = .{
...@@ -4087,10 +4090,15 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -4087,10 +4090,15 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
40874090
4088 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;4091 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4089 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });4092 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
4093
4090 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);4094 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
4091 if (block.is_comptime) {4095 if (block.is_comptime) {
4092 return sema.analyzeComptimeAlloc(block, var_ty, .none);4096 return sema.analyzeComptimeAlloc(block, var_ty, .none);
4093 }4097 }
4098 if (sema.func_is_naked and try sema.typeHasRuntimeBits(var_ty)) {
4099 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
4100 return sema.fail(block, mut_src, "local variable in naked function", .{});
4101 }
4094 const target = pt.zcu.getTarget();4102 const target = pt.zcu.getTarget();
4095 const ptr_type = try pt.ptrTypeSema(.{4103 const ptr_type = try pt.ptrTypeSema(.{
4096 .child = var_ty.toIntern(),4104 .child = var_ty.toIntern(),
...@@ -4115,6 +4123,10 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -4115,6 +4123,10 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
4115 if (block.is_comptime) {4123 if (block.is_comptime) {
4116 return sema.analyzeComptimeAlloc(block, var_ty, .none);4124 return sema.analyzeComptimeAlloc(block, var_ty, .none);
4117 }4125 }
4126 if (sema.func_is_naked and try sema.typeHasRuntimeBits(var_ty)) {
4127 const var_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
4128 return sema.fail(block, var_src, "local variable in naked function", .{});
4129 }
4118 try sema.validateVarType(block, ty_src, var_ty, false);4130 try sema.validateVarType(block, ty_src, var_ty, false);
4119 const target = pt.zcu.getTarget();4131 const target = pt.zcu.getTarget();
4120 const ptr_type = try pt.ptrTypeSema(.{4132 const ptr_type = try pt.ptrTypeSema(.{
...@@ -4248,7 +4260,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4248,7 +4260,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4248 // TODO: source location of runtime control flow4260 // TODO: source location of runtime control flow
4249 return sema.fail(block, src, "value with comptime-only type '{}' depends on runtime control flow", .{final_elem_ty.fmt(pt)});4261 return sema.fail(block, src, "value with comptime-only type '{}' depends on runtime control flow", .{final_elem_ty.fmt(pt)});
4250 }4262 }
42514263 if (sema.func_is_naked and try sema.typeHasRuntimeBits(final_elem_ty)) {
4264 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
4265 return sema.fail(block, mut_src, "local variable in naked function", .{});
4266 }
4252 // Change it to a normal alloc.4267 // Change it to a normal alloc.
4253 sema.air_instructions.set(@intFromEnum(ptr_inst), .{4268 sema.air_instructions.set(@intFromEnum(ptr_inst), .{
4254 .tag = .alloc,4269 .tag = .alloc,
test/cases/compile_errors/stack_usage_in_naked_function.zig created+45
...@@ -0,0 +1,45 @@
1export fn a() callconv(.Naked) noreturn {
2 var x: u32 = 10;
3 _ = &x;
4
5 const y: u32 = x + 10;
6 _ = y;
7}
8
9export fn b() callconv(.Naked) noreturn {
10 var x = @as(u32, 10);
11 _ = &x;
12
13 const y = x;
14 var z = y;
15 _ = &z;
16}
17
18export fn c() callconv(.Naked) noreturn {
19 const Foo = struct {
20 y: u32,
21 };
22
23 var x: Foo = .{ .y = 10 };
24 _ = &x;
25}
26
27export fn d() callconv(.Naked) noreturn {
28 const Foo = struct {
29 inline fn bar() void {
30 var x: u32 = 10;
31 _ = &x;
32 }
33 };
34
35 Foo.bar();
36}
37
38// error
39// backend=stage2
40//
41// :2:5: error: local variable in naked function
42// :10:5: error: local variable in naked function
43// :23:5: error: local variable in naked function
44// :30:13: error: local variable in naked function
45// :35:12: note: called from here