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 f7d8aef12d617ea3bdcad29d576e0aa6867f6674..550f51d7c5e703426b2777550da693239e3d1b83 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); -- 2.54.0 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 abb1eb0a99e9e4733ddcce07571f92251047180d..52c202fdedac147ed23adba1c4a81dcfaf0d0f03 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); } -- 2.54.0 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 4275a1b69d0d6dbc7be3bf76f2cb7e5951070a21..4333b34d98554cc2e70d49b53fb5375f9217ad9e 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; } -- 2.54.0 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 4333b34d98554cc2e70d49b53fb5375f9217ad9e..8857c96bc11eb7fb75493ce1e0d4dd1ea37fea22 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. -- 2.54.0 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 d962bfd854156c8cf5e01b07619a71987da7dced..80dcba3f6fbd3eb308c382870397bb7ce506947c 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 13322c9bee5fead90706b030e42f8817a6af9d08..b0338bdf2065887ca2b5b42c6f784e7d8ebe3579 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 e0204b3bc51103684d223b3a17029962f647e0d0..e8db9a3e0ecbf9ff958183bd5d5c0b3bd3fff665 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() -- 2.54.0