From e02b9f458dd7e48bef5b436242ba0ab3550224da Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 6 Sep 2022 13:28:31 +0200 Subject: build-exe: allow combination of -fno-emit-bin and --verbose-air Currently, `zig build-exe -fno-emit-bin --verbose-air src/main.zig` results in no output at all. With this refactor, it dumps AIR and then exits without invoking LLVM, as expected --- src/Module.zig | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index c63fe43158..3ae6c48edd 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4274,11 +4274,14 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { const comp = mod.comp; - if (comp.bin_file.options.emit == null and + const no_bin_file = (comp.bin_file.options.emit == null and comp.emit_asm == null and comp.emit_llvm_ir == null and - comp.emit_llvm_bc == null) - { + comp.emit_llvm_bc == null); + + const dump_air = builtin.mode == .Debug and comp.verbose_air; + + if (no_bin_file and !dump_air) { return; } @@ -4286,7 +4289,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { var liveness = try Liveness.analyze(gpa, air); defer liveness.deinit(gpa); - if (builtin.mode == .Debug and comp.verbose_air) { + if (dump_air) { const fqn = try decl.getFullyQualifiedName(mod); defer mod.gpa.free(fqn); @@ -4295,6 +4298,10 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { std.debug.print("# End Function AIR: {s}\n\n", .{fqn}); } + if (no_bin_file) { + return; + } + comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => { -- cgit v1.2.3 From 99826a2ba89ccd80caaa4eeb47c59a71ddfe76b6 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 7 Sep 2022 22:05:01 +0300 Subject: Sema: fix UAF in zirClosureGet Previously if a decl failed its capture scope would be deallocated and set to undefined which would then lead to invalid dereference in `zirClosureGet`. To avoid this set the capture scope to a special failed state and fail the current decl with dependency failure if the failed state is encountered in `zirClosureGet`. Closes #12433 Closes #12530 Closes #12593 --- src/Module.zig | 10 +++++++++ src/Sema.zig | 11 ++++++++- .../closure_get_depends_on_failed_decl.zig | 26 ++++++++++++++++++++++ ...ure_get_in_param_ty_instantiate_incorrectly.zig | 24 ++++++++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 test/cases/compile_errors/closure_get_depends_on_failed_decl.zig create mode 100644 test/cases/compile_errors/closure_get_in_param_ty_instantiate_incorrectly.zig (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 3ae6c48edd..ea89225537 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -345,6 +345,15 @@ pub const CaptureScope = struct { /// During sema, this map is backed by the gpa. Once sema completes, /// it is reallocated using the value_arena. captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, TypedValue) = .{}, + + pub fn failed(noalias self: *const @This()) bool { + return self.captures.available == 0 and self.captures.size == std.math.maxInt(u32); + } + + pub fn fail(noalias self: *@This()) void { + self.captures.available = 0; + self.captures.size = std.math.maxInt(u32); + } }; pub const WipCaptureScope = struct { @@ -383,6 +392,7 @@ pub const WipCaptureScope = struct { pub fn deinit(noalias self: *@This()) void { if (!self.finalized) { self.scope.captures.deinit(self.gpa); + self.scope.fail(); } self.* = undefined; } diff --git a/src/Sema.zig b/src/Sema.zig index 8d25a7c93e..15e891ef87 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5956,7 +5956,6 @@ fn analyzeCall( error.NeededSourceLocation => { _ = sema.inst_map.remove(inst); const decl = sema.mod.declPtr(block.src_decl); - child_block.src_decl = block.src_decl; try sema.analyzeInlineCallArg( block, &child_block, @@ -13740,6 +13739,16 @@ fn zirClosureGet( const tv = while (true) { // Note: We don't need to add a dependency here, because // decls always depend on their lexical parents. + + // Fail this decl if a scope it depended on failed. + if (scope.failed()) { + if (sema.owner_func) |owner_func| { + owner_func.state = .dependency_failure; + } else { + sema.owner_decl.analysis = .dependency_failure; + } + return error.AnalysisFail; + } if (scope.captures.getPtr(inst_data.inst)) |tv| { break tv; } diff --git a/test/cases/compile_errors/closure_get_depends_on_failed_decl.zig b/test/cases/compile_errors/closure_get_depends_on_failed_decl.zig new file mode 100644 index 0000000000..ccdbf67713 --- /dev/null +++ b/test/cases/compile_errors/closure_get_depends_on_failed_decl.zig @@ -0,0 +1,26 @@ +pub inline fn instanceRequestAdapter() void {} + +pub inline fn requestAdapter( + comptime callbackArg: fn () callconv(.Inline) void, +) void { + _ = (struct { + pub fn callback() callconv(.C) void { + callbackArg(); + } + }).callback; + instanceRequestAdapter(undefined); // note wrong number of arguments here +} + +inline fn foo() void {} + +pub export fn entry() void { + requestAdapter(foo); +} + +// error +// backend=stage2 +// target=native +// +// :11:5: error: expected 0 argument(s), found 1 +// :1:12: note: function declared here +// :17:19: note: called from here diff --git a/test/cases/compile_errors/closure_get_in_param_ty_instantiate_incorrectly.zig b/test/cases/compile_errors/closure_get_in_param_ty_instantiate_incorrectly.zig new file mode 100644 index 0000000000..dc533442fb --- /dev/null +++ b/test/cases/compile_errors/closure_get_in_param_ty_instantiate_incorrectly.zig @@ -0,0 +1,24 @@ +fn Observable(comptime T: type) type { + return struct { + fn map(Src: T, Dst: anytype, function: fn (T) Dst) Dst { + _ = Src; + _ = function; + return Observable(Dst); + } + }; +} + +fn u32Tou64(x: u32) u64 { + _ = x; + return 0; +} + +pub export fn entry() void { + Observable(u32).map(u32, u64, u32Tou64(0)); +} + +// error +// backend=stage2 +// target=native +// +// :17:25: error: expected type 'u32', found 'type' -- cgit v1.2.3