From 56f2e5c5bc3267fa6c54d8fbc2295c5fa2a21571 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Jul 2022 14:51:22 -0700 Subject: [PATCH 1/5] Sema: fix double-free on compile errors when instantiating a generic function and an error occurs in the function prototype. --- src/Sema.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Sema.zig b/src/Sema.zig index f7d8aef12d..550f51d7c5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7096,6 +7096,7 @@ fn funcCommon( if (param.ty.tag() == .generic_poison) is_generic = true; } + var destroy_fn_on_error = false; const new_func: *Module.Fn = new_func: { if (!has_body) break :new_func undefined; if (sema.comptime_args_fn_inst == func_inst) { @@ -7103,9 +7104,10 @@ fn funcCommon( sema.preallocated_new_func = null; // take ownership break :new_func new_func; } + destroy_fn_on_error = true; break :new_func try sema.gpa.create(Module.Fn); }; - errdefer if (has_body) sema.gpa.destroy(new_func); + errdefer if (destroy_fn_on_error) sema.gpa.destroy(new_func); var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null; errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node); From d789c687172166fe599d6b4cec2993f25f75989e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Jul 2022 16:41:41 -0700 Subject: [PATCH 2/5] zig_llvm: include Debug Info Version even for CodeView I mistakenly thought this was supposed to only be present for Dwarf. --- src/zig_llvm.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index abb1eb0a99..52c202fded 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -1134,6 +1134,7 @@ void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module) { } void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) { + unwrap(module)->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION); unwrap(module)->addModuleFlag(Module::Warning, "CodeView", 1); } From 0d164f9a25f05a2917f4e1d4eb21c85b3279b47b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Jul 2022 16:44:09 -0700 Subject: [PATCH 3/5] LLVM: broaden aarch64-windows f16 debug variable workaround LLVM does not properly handle debug info for f16 on the aarch64-windows target, causing "fatal error: unknown codeview register H1". The previous workaround checked only for f16 but was still vulnerable if a type was a byval struct or tuple which had an f16 field in it. Now I have filed an upstream issue (see https://github.com/llvm/llvm-project/issues/56484) and broadened the workaround to always skip debug values for this target. --- src/codegen/llvm.zig | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 4275a1b69d..4333b34d98 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5244,7 +5244,7 @@ pub const FuncGen = struct { const operand_ty = self.air.typeOf(pl_op.operand); const name = self.air.nullTerminatedString(pl_op.payload); - if (needDbgVarWorkaround(self.dg, operand_ty)) { + if (needDbgVarWorkaround(self.dg)) { return null; } @@ -6988,7 +6988,7 @@ pub const FuncGen = struct { const inst_ty = self.air.typeOfIndex(inst); if (self.dg.object.di_builder) |dib| { - if (needDbgVarWorkaround(self.dg, inst_ty)) { + if (needDbgVarWorkaround(self.dg)) { return arg_val; } @@ -9255,13 +9255,11 @@ const AnnotatedDITypePtr = enum(usize) { const lt_errors_fn_name = "__zig_lt_errors_len"; /// Without this workaround, LLVM crashes with "unknown codeview register H1" -/// TODO use llvm-reduce and file upstream LLVM bug for this. -fn needDbgVarWorkaround(dg: *DeclGen, ty: Type) bool { - if (ty.tag() == .f16) { - const target = dg.module.getTarget(); - if (target.os.tag == .windows and target.cpu.arch == .aarch64) { - return true; - } +/// https://github.com/llvm/llvm-project/issues/56484 +fn needDbgVarWorkaround(dg: *DeclGen) bool { + const target = dg.module.getTarget(); + if (target.os.tag == .windows and target.cpu.arch == .aarch64) { + return true; } return false; } From 8324a93f2e382036b3a923f4ac869cf0d80438a2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Jul 2022 18:41:59 -0700 Subject: [PATCH 4/5] LLVM: always add some clobbers for some architectures For some targets, Clang unconditionally adds some clobbers to all inline assembly. While this is probably not strictly necessary, if we don't follow Clang's lead here then we may risk tripping LLVM bugs since anything not used by Clang tends to be buggy and regress often. --- src/codegen/llvm.zig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 4333b34d98..8857c96bc1 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5432,6 +5432,25 @@ pub const FuncGen = struct { total_i += 1; } } + + // For some targets, Clang unconditionally adds some clobbers to all inline assembly. + // While this is probably not strictly necessary, if we don't follow Clang's lead + // here then we may risk tripping LLVM bugs since anything not used by Clang tends + // to be buggy and regress often. + switch (target.cpu.arch) { + .x86_64, .i386 => { + if (total_i != 0) try llvm_constraints.append(self.gpa, ','); + try llvm_constraints.appendSlice(self.gpa, "~{dirflag},~{fpsr},~{flags}"); + total_i += 3; + }, + .mips, .mipsel, .mips64, .mips64el => { + if (total_i != 0) try llvm_constraints.append(self.gpa, ','); + try llvm_constraints.appendSlice(self.gpa, "~{$1}"); + total_i += 1; + }, + else => {}, + } + const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; // hackety hacks until stage2 has proper inline asm in the frontend. From 6ab5219e34d385e29df9b2a014ed89b9db343740 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Jul 2022 20:39:05 -0700 Subject: [PATCH 5/5] std: update test cases to reflect new packed struct semantics --- lib/std/io/c_writer.zig | 2 +- lib/std/mem.zig | 32 ++++++++++++++++++++------------ lib/std/x/net/bpf.zig | 10 +++------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/lib/std/io/c_writer.zig b/lib/std/io/c_writer.zig index d962bfd854..80dcba3f6f 100644 --- a/lib/std/io/c_writer.zig +++ b/lib/std/io/c_writer.zig @@ -30,7 +30,7 @@ fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!u } } -test { +test "C Writer" { if (!builtin.link_libc or builtin.os.tag == .wasi) return error.SkipZigTest; const filename = "tmp_io_test_file.txt"; diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 13322c9bee..b0338bdf20 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -2831,6 +2831,8 @@ pub fn asBytes(ptr: anytype) AsBytesReturnType(@TypeOf(ptr)) { } test "asBytes" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + const deadbeef = @as(u32, 0xDEADBEEF); const deadbeef_bytes = switch (native_endian) { .Big => "\xDE\xAD\xBE\xEF", @@ -2857,7 +2859,14 @@ test "asBytes" { .c = 0xDE, .d = 0xA1, }; - try testing.expect(eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1")); + switch (native_endian) { + .Little => { + try testing.expect(eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1")); + }, + .Big => { + try testing.expect(eql(u8, asBytes(&inst), "\xA1\xDE\xEF\xBE")); + }, + } const ZST = struct {}; const zero = ZST{}; @@ -2917,6 +2926,8 @@ pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, } test "bytesAsValue" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + const deadbeef = @as(u32, 0xDEADBEEF); const deadbeef_bytes = switch (native_endian) { .Big => "\xDE\xAD\xBE\xEF", @@ -2948,7 +2959,10 @@ test "bytesAsValue" { .c = 0xDE, .d = 0xA1, }; - const inst_bytes = "\xBE\xEF\xDE\xA1"; + const inst_bytes = switch (native_endian) { + .Little => "\xBE\xEF\xDE\xA1", + .Big => "\xA1\xDE\xEF\xBE", + }; const inst2 = bytesAsValue(S, inst_bytes); try testing.expect(meta.eql(inst, inst2.*)); } @@ -3115,6 +3129,8 @@ test "sliceAsBytes with sentinel slice" { } test "sliceAsBytes packed struct at runtime and comptime" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + const Foo = packed struct { a: u4, b: u4, @@ -3124,16 +3140,8 @@ test "sliceAsBytes packed struct at runtime and comptime" { var foo: Foo = undefined; var slice = sliceAsBytes(@as(*[1]Foo, &foo)[0..1]); slice[0] = 0x13; - switch (native_endian) { - .Big => { - try testing.expect(foo.a == 0x1); - try testing.expect(foo.b == 0x3); - }, - .Little => { - try testing.expect(foo.a == 0x3); - try testing.expect(foo.b == 0x1); - }, - } + try testing.expect(foo.a == 0x3); + try testing.expect(foo.b == 0x1); } }; try S.doTheTest(); diff --git a/lib/std/x/net/bpf.zig b/lib/std/x/net/bpf.zig index e0204b3bc5..e8db9a3e0e 100644 --- a/lib/std/x/net/bpf.zig +++ b/lib/std/x/net/bpf.zig @@ -706,12 +706,8 @@ fn expectFail(expected_error: anyerror, data: anytype, filter: []Insn) !void { } test "simulator coverage" { - const some_data: packed struct { - foo: u32, - bar: u8, - } = .{ - .foo = mem.nativeToBig(u32, 0xaabbccdd), - .bar = 0x7f, + const some_data = [_]u8{ + 0xaa, 0xbb, 0xcc, 0xdd, 0x7f, }; try expectPass(&some_data, &.{ @@ -764,7 +760,7 @@ test "simulator coverage" { // ld #len // fail if A != 5 Insn.ld_len(), - Insn.jmp(.jeq, .{ .k = @sizeOf(@TypeOf(some_data)) }, 1, 0), + Insn.jmp(.jeq, .{ .k = some_data.len }, 1, 0), Insn.ret(.{ .k = 9 }), // ld #0 // ld arc4random()