From 87779cfd93fdcb525f386d693a099e4188a3fc44 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 16 Mar 2022 23:54:25 -0700 Subject: [PATCH] stage2: prevent UB in the LLVM backend * Sema: fix `zirTypeInfo` allocating with the wrong arenas for some stuff. * LLVM: split `airDbgInline` into two functions, one for each AIR tag. - remove the redundant copy to type_map_arena. This is the first thing that lowerDebugType does so this hack was probably just accidentally avoiding UB (which is still present prior to this commit). - don't store an inline fn inst into the di_map for the generic decl. - use a dummy function type for the debug info to avoid whatever UB is happening. - we are now ignoring the function type passed in with the dbg_inline_begin and dbg_inline_end. * behavior tests: prepare the vector tests to be enabled one at a time. Mitigates #11199. --- src/Sema.zig | 8 +++---- src/codegen/llvm.zig | 50 ++++++++++++++++++++-------------------- test/behavior.zig | 2 +- test/behavior/vector.zig | 25 ++++++++++++++++++++ 4 files changed, 55 insertions(+), 30 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index cc52f6c549..c6de8cf5dc 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10907,9 +10907,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), ); - break :v try Value.Tag.slice.create(sema.arena, .{ + break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), - .len = try Value.Tag.int_u64.create(sema.arena, bytes.len), + .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len), }); }; @@ -10950,9 +10950,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), ); - break :v try Value.Tag.slice.create(sema.arena, .{ + break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), - .len = try Value.Tag.int_u64.create(sema.arena, bytes.len), + .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len), }); }; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index b41611813e..8fb2a171ef 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3472,8 +3472,8 @@ pub const FuncGen = struct { .const_ty => unreachable, .unreach => self.airUnreach(inst), .dbg_stmt => self.airDbgStmt(inst), - .dbg_inline_begin => try self.airDbgInline(inst, true), - .dbg_inline_end => try self.airDbgInline(inst, false), + .dbg_inline_begin => try self.airDbgInlineBegin(inst), + .dbg_inline_end => try self.airDbgInlineEnd(inst), .dbg_var_ptr => try self.airDbgVarPtr(inst), .dbg_var_val => try self.airDbgVarVal(inst), // zig fmt: on @@ -4199,7 +4199,7 @@ pub const FuncGen = struct { return null; } - fn airDbgInline(self: *FuncGen, inst: Air.Inst.Index, start: bool) !?*const llvm.Value { + fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { const dib = self.dg.object.di_builder orelse return null; const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; @@ -4209,52 +4209,52 @@ pub const FuncGen = struct { self.di_file = di_file; const line_number = decl.src_line + 1; const cur_debug_location = self.builder.getCurrentDebugLocation2(); - if (start) { - try self.dbg_inlined.append(self.gpa, .{ - .loc = @ptrCast(*llvm.DILocation, cur_debug_location), - .scope = self.di_scope.?, - .base_line = self.base_line, - }); - } else { - const old = self.dbg_inlined.pop(); - self.di_scope = old.scope; - self.base_line = old.base_line; - return null; - } - const fn_ty = try self.air.getRefType(ty_pl.ty).copy(self.dg.object.type_map_arena.allocator()); + try self.dbg_inlined.append(self.gpa, .{ + .loc = @ptrCast(*llvm.DILocation, cur_debug_location), + .scope = self.di_scope.?, + .base_line = self.base_line, + }); + const fqn = try decl.getFullyQualifiedName(self.gpa); defer self.gpa.free(fqn); - const fn_info = fn_ty.fnInfo(); const is_internal_linkage = !self.dg.module.decl_exports.contains(decl); - const noret_bit: c_uint = if (fn_info.return_type.isNoReturn()) - llvm.DIFlags.NoReturn - else - 0; const subprogram = dib.createFunction( di_file.toScope(), decl.name, fqn, di_file, line_number, - try self.dg.object.lowerDebugType(fn_ty, .full), + try self.dg.object.lowerDebugType(Type.initTag(.fn_void_no_args), .full), is_internal_linkage, true, // is definition line_number + func.lbrace_line, // scope line - llvm.DIFlags.StaticMember | noret_bit, + llvm.DIFlags.StaticMember, self.dg.module.comp.bin_file.options.optimize_mode != .Debug, null, // decl_subprogram ); - try self.dg.object.di_map.put(self.gpa, decl, subprogram.toNode()); - const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1); self.di_scope = lexical_block.toScope(); self.base_line = decl.src_line; return null; } + fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + if (self.dg.object.di_builder == null) return null; + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + + const func = self.air.values[ty_pl.payload].castTag(.function).?.data; + const decl = func.owner_decl; + const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope); + self.di_file = di_file; + const old = self.dbg_inlined.pop(); + self.di_scope = old.scope; + self.base_line = old.base_line; + return null; + } + fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { const dib = self.dg.object.di_builder orelse return null; const pl_op = self.air.instructions.items(.data)[inst].pl_op; diff --git a/test/behavior.zig b/test/behavior.zig index f142464dc3..67fd25b04d 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -125,6 +125,7 @@ test { _ = @import("behavior/union.zig"); _ = @import("behavior/usingnamespace.zig"); _ = @import("behavior/var_args.zig"); + _ = @import("behavior/vector.zig"); _ = @import("behavior/void.zig"); _ = @import("behavior/while.zig"); @@ -179,7 +180,6 @@ test { _ = @import("behavior/select.zig"); _ = @import("behavior/struct_contains_slice_of_itself.zig"); _ = @import("behavior/typename.zig"); - _ = @import("behavior/vector.zig"); } } } diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 946aba0949..788ef3b62a 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -8,6 +8,7 @@ const expectApproxEqRel = std.testing.expectApproxEqRel; const Vector = std.meta.Vector; test "implicit cast vector to array - bool" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { const a: Vector(4, bool) = [_]bool{ true, false, true, false }; @@ -20,6 +21,7 @@ test "implicit cast vector to array - bool" { } test "vector wrap operators" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; @@ -36,6 +38,7 @@ test "vector wrap operators" { } test "vector bin compares with mem.eql" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; @@ -53,6 +56,7 @@ test "vector bin compares with mem.eql" { } test "vector int operators" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; @@ -68,6 +72,7 @@ test "vector int operators" { } test "vector float operators" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, f32) = [4]f32{ 10, 20, 30, 40 }; @@ -83,6 +88,7 @@ test "vector float operators" { } test "vector bit operators" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 }; @@ -97,6 +103,7 @@ test "vector bit operators" { } test "implicit cast vector to array" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var a: Vector(4, i32) = [_]i32{ 1, 2, 3, 4 }; @@ -110,6 +117,7 @@ test "implicit cast vector to array" { } test "array to vector" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO var foo: f32 = 3.14; var arr = [4]f32{ foo, 1.5, 0.0, 0.0 }; var vec: Vector(4, f32) = arr; @@ -117,6 +125,7 @@ test "array to vector" { } test "vector casts of sizes not divisible by 8" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { { @@ -146,6 +155,7 @@ test "vector casts of sizes not divisible by 8" { } test "vector @splat" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn testForT(comptime N: comptime_int, v: anytype) !void { const T = @TypeOf(v); @@ -181,6 +191,7 @@ test "vector @splat" { } test "load vector elements via comptime index" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; @@ -198,6 +209,7 @@ test "load vector elements via comptime index" { } test "store vector elements via comptime index" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; @@ -221,6 +233,7 @@ test "store vector elements via comptime index" { } test "load vector elements via runtime index" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; @@ -238,6 +251,7 @@ test "load vector elements via runtime index" { } test "store vector elements via runtime index" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; @@ -256,6 +270,7 @@ test "store vector elements via runtime index" { } test "initialize vector which is a struct field" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const Vec4Obj = struct { data: Vector(4, f32), }; @@ -273,6 +288,7 @@ test "initialize vector which is a struct field" { } test "vector comparison operators" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { { @@ -307,6 +323,7 @@ test "vector comparison operators" { } test "vector division operators" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTestDiv(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void { if (!comptime std.meta.trait.isSignedInt(T)) { @@ -389,6 +406,7 @@ test "vector division operators" { } test "vector bitwise not operator" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTestNot(comptime T: type, x: Vector(4, T)) !void { var y = ~x; @@ -414,6 +432,7 @@ test "vector bitwise not operator" { } test "vector shift operators" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTestShift(x: anytype, y: anytype) !void { const N = @typeInfo(@TypeOf(x)).Array.len; @@ -501,6 +520,7 @@ test "vector shift operators" { } test "vector reduce operation" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTestReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void { const N = @typeInfo(@TypeOf(x)).Array.len; @@ -636,6 +656,7 @@ test "vector reduce operation" { } test "mask parameter of @shuffle is comptime scope" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const __v4hi = std.meta.Vector(4, i16); var v4_a = __v4hi{ 0, 0, 0, 0 }; var v4_b = __v4hi{ 0, 0, 0, 0 }; @@ -649,6 +670,7 @@ test "mask parameter of @shuffle is comptime scope" { } test "saturating add" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { const u8x3 = std.meta.Vector(3, u8); @@ -662,6 +684,7 @@ test "saturating add" { } test "saturating subtraction" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { const u8x3 = std.meta.Vector(3, u8); @@ -673,6 +696,7 @@ test "saturating subtraction" { } test "saturating multiplication" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO // TODO: once #9660 has been solved, remove this line if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest; @@ -688,6 +712,7 @@ test "saturating multiplication" { } test "saturating shift-left" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { const u8x3 = std.meta.Vector(3, u8);