Commit 87779cfd93

Andrew Kelley <andrew@ziglang.org>
2022-03-17 07:54:25
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.
1 parent 79d3780
Changed files (4)
src
test
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;
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),
                         });
                     };
 
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);
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");
             }
         }
     }