authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-08 14:55:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-08 15:03:03-07:00
logfb4ad37e0bd07513a0a56afb45e95c68036b1eea
treea735a6104ec10aae6417b7e11d4b893debb06776
parent874b51d8d4d80f224e979adba11526a5dcec61da

LLVM: fix memory leak of debug type names

This required adjusting `Type.nameAlloc` to be used with a general-purpose allocator and added `Type.nameAllocArena` for the arena use case (avoids allocation sometimes).

4 files changed, 80 insertions(+), 50 deletions(-)

src/Sema.zig+1-1
...@@ -12405,7 +12405,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12405,7 +12405,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12405 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);12405 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
12406 defer anon_decl.deinit();12406 defer anon_decl.deinit();
1240712407
12408 const bytes = try ty.nameAlloc(anon_decl.arena());12408 const bytes = try ty.nameAllocArena(anon_decl.arena());
1240912409
12410 const new_decl = try anon_decl.finish(12410 const new_decl = try anon_decl.finish(
12411 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),12411 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
src/codegen/llvm.zig+20-10
...@@ -1922,7 +1922,8 @@ pub const DeclGen = struct {...@@ -1922,7 +1922,8 @@ pub const DeclGen = struct {
1922 .Int => {1922 .Int => {
1923 const info = ty.intInfo(target);1923 const info = ty.intInfo(target);
1924 assert(info.bits != 0);1924 assert(info.bits != 0);
1925 const name = try ty.nameAlloc(gpa); // TODO this is a leak1925 const name = try ty.nameAlloc(gpa);
1926 defer gpa.free(name);
1926 const dwarf_encoding: c_uint = switch (info.signedness) {1927 const dwarf_encoding: c_uint = switch (info.signedness) {
1927 .signed => DW.ATE.signed,1928 .signed => DW.ATE.signed,
1928 .unsigned => DW.ATE.unsigned,1929 .unsigned => DW.ATE.unsigned,
...@@ -1967,7 +1968,8 @@ pub const DeclGen = struct {...@@ -1967,7 +1968,8 @@ pub const DeclGen = struct {
1967 const di_file = try dg.object.getDIFile(gpa, owner_decl.src_namespace.file_scope);1968 const di_file = try dg.object.getDIFile(gpa, owner_decl.src_namespace.file_scope);
1968 const di_scope = try dg.namespaceToDebugScope(owner_decl.src_namespace);1969 const di_scope = try dg.namespaceToDebugScope(owner_decl.src_namespace);
19691970
1970 const name = try ty.nameAlloc(gpa); // TODO this is a leak1971 const name = try ty.nameAlloc(gpa);
1972 defer gpa.free(name);
1971 var buffer: Type.Payload.Bits = undefined;1973 var buffer: Type.Payload.Bits = undefined;
1972 const int_ty = ty.intTagType(&buffer);1974 const int_ty = ty.intTagType(&buffer);
19731975
...@@ -1989,7 +1991,8 @@ pub const DeclGen = struct {...@@ -1989,7 +1991,8 @@ pub const DeclGen = struct {
1989 },1991 },
1990 .Float => {1992 .Float => {
1991 const bits = ty.floatBits(target);1993 const bits = ty.floatBits(target);
1992 const name = try ty.nameAlloc(gpa); // TODO this is a leak1994 const name = try ty.nameAlloc(gpa);
1995 defer gpa.free(name);
1993 gop.value_ptr.* = dib.createBasicType(name, bits, DW.ATE.float);1996 gop.value_ptr.* = dib.createBasicType(name, bits, DW.ATE.float);
1994 return gop.value_ptr.*;1997 return gop.value_ptr.*;
1995 },1998 },
...@@ -2039,7 +2042,8 @@ pub const DeclGen = struct {...@@ -2039,7 +2042,8 @@ pub const DeclGen = struct {
2039 const ptr_ty = ty.slicePtrFieldType(&buf);2042 const ptr_ty = ty.slicePtrFieldType(&buf);
2040 const len_ty = Type.usize;2043 const len_ty = Type.usize;
20412044
2042 const name = try ty.nameAlloc(gpa); // TODO this is a leak2045 const name = try ty.nameAlloc(gpa);
2046 defer gpa.free(name);
2043 const di_file: ?*llvm.DIFile = null;2047 const di_file: ?*llvm.DIFile = null;
2044 const line = 0;2048 const line = 0;
2045 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();2049 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
...@@ -2109,7 +2113,8 @@ pub const DeclGen = struct {...@@ -2109,7 +2113,8 @@ pub const DeclGen = struct {
2109 }2113 }
21102114
2111 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);2115 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);
2112 const name = try ty.nameAlloc(gpa); // TODO this is a leak2116 const name = try ty.nameAlloc(gpa);
2117 defer gpa.free(name);
2113 const ptr_di_ty = dib.createPointerType(2118 const ptr_di_ty = dib.createPointerType(
2114 elem_di_ty,2119 elem_di_ty,
2115 target.cpu.arch.ptrBitWidth(),2120 target.cpu.arch.ptrBitWidth(),
...@@ -2125,7 +2130,8 @@ pub const DeclGen = struct {...@@ -2125,7 +2130,8 @@ pub const DeclGen = struct {
2125 gop.value_ptr.* = dib.createBasicType("anyopaque", 0, DW.ATE.signed);2130 gop.value_ptr.* = dib.createBasicType("anyopaque", 0, DW.ATE.signed);
2126 return gop.value_ptr.*;2131 return gop.value_ptr.*;
2127 }2132 }
2128 const name = try ty.nameAlloc(gpa); // TODO this is a leak2133 const name = try ty.nameAlloc(gpa);
2134 defer gpa.free(name);
2129 const owner_decl = ty.getOwnerDecl();2135 const owner_decl = ty.getOwnerDecl();
2130 const opaque_di_ty = dib.createForwardDeclType(2136 const opaque_di_ty = dib.createForwardDeclType(
2131 DW.TAG.structure_type,2137 DW.TAG.structure_type,
...@@ -2162,7 +2168,8 @@ pub const DeclGen = struct {...@@ -2162,7 +2168,8 @@ pub const DeclGen = struct {
2162 return vector_di_ty;2168 return vector_di_ty;
2163 },2169 },
2164 .Optional => {2170 .Optional => {
2165 const name = try ty.nameAlloc(gpa); // TODO this is a leak2171 const name = try ty.nameAlloc(gpa);
2172 defer gpa.free(name);
2166 var buf: Type.Payload.ElemType = undefined;2173 var buf: Type.Payload.ElemType = undefined;
2167 const child_ty = ty.optionalChild(&buf);2174 const child_ty = ty.optionalChild(&buf);
2168 if (!child_ty.hasRuntimeBits()) {2175 if (!child_ty.hasRuntimeBits()) {
...@@ -2253,7 +2260,8 @@ pub const DeclGen = struct {...@@ -2253,7 +2260,8 @@ pub const DeclGen = struct {
2253 try dg.object.di_type_map.put(gpa, ty, err_set_di_ty);2260 try dg.object.di_type_map.put(gpa, ty, err_set_di_ty);
2254 return err_set_di_ty;2261 return err_set_di_ty;
2255 }2262 }
2256 const name = try ty.nameAlloc(gpa); // TODO this is a leak2263 const name = try ty.nameAlloc(gpa);
2264 defer gpa.free(name);
2257 const di_file: ?*llvm.DIFile = null;2265 const di_file: ?*llvm.DIFile = null;
2258 const line = 0;2266 const line = 0;
2259 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();2267 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
...@@ -2329,7 +2337,8 @@ pub const DeclGen = struct {...@@ -2329,7 +2337,8 @@ pub const DeclGen = struct {
2329 },2337 },
2330 .Struct => {2338 .Struct => {
2331 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();2339 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
2332 const name = try ty.nameAlloc(gpa); // TODO this is a leak2340 const name = try ty.nameAlloc(gpa);
2341 defer gpa.free(name);
2333 const fwd_decl = dib.createReplaceableCompositeType(2342 const fwd_decl = dib.createReplaceableCompositeType(
2334 DW.TAG.structure_type,2343 DW.TAG.structure_type,
2335 name.ptr,2344 name.ptr,
...@@ -2477,7 +2486,8 @@ pub const DeclGen = struct {...@@ -2477,7 +2486,8 @@ pub const DeclGen = struct {
2477 .Union => {2486 .Union => {
2478 const owner_decl = ty.getOwnerDecl();2487 const owner_decl = ty.getOwnerDecl();
24792488
2480 const name = try ty.nameAlloc(gpa); // TODO this is a leak2489 const name = try ty.nameAlloc(gpa);
2490 defer gpa.free(name);
2481 const fwd_decl = dib.createReplaceableCompositeType(2491 const fwd_decl = dib.createReplaceableCompositeType(
2482 DW.TAG.structure_type,2492 DW.TAG.structure_type,
2483 name.ptr,2493 name.ptr,
src/link/Dwarf.zig+1-1
...@@ -882,7 +882,7 @@ fn addDbgInfoType(...@@ -882,7 +882,7 @@ fn addDbgInfoType(
882 const abi_size = ty.abiSize(target);882 const abi_size = ty.abiSize(target);
883 try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);883 try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
884 // DW.AT.name, DW.FORM.string884 // DW.AT.name, DW.FORM.string
885 const struct_name = try ty.nameAlloc(arena);885 const struct_name = try ty.nameAllocArena(arena);
886 try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1);886 try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1);
887 dbg_info_buffer.appendSliceAssumeCapacity(struct_name);887 dbg_info_buffer.appendSliceAssumeCapacity(struct_name);
888 dbg_info_buffer.appendAssumeCapacity(0);888 dbg_info_buffer.appendAssumeCapacity(0);
src/type.zig+58-38
...@@ -1766,8 +1766,20 @@ pub const Type = extern union {...@@ -1766,8 +1766,20 @@ pub const Type = extern union {
1766 }1766 }
1767 }1767 }
17681768
1769 pub fn nameAllocArena(ty: Type, arena: Allocator) Allocator.Error![:0]const u8 {
1770 return nameAllocAdvanced(ty, arena, true);
1771 }
1772
1773 pub fn nameAlloc(ty: Type, gpa: Allocator) Allocator.Error![:0]const u8 {
1774 return nameAllocAdvanced(ty, gpa, false);
1775 }
1776
1769 /// Returns a name suitable for `@typeName`.1777 /// Returns a name suitable for `@typeName`.
1770 pub fn nameAlloc(ty: Type, arena: Allocator) Allocator.Error![:0]const u8 {1778 pub fn nameAllocAdvanced(
1779 ty: Type,
1780 ally: Allocator,
1781 is_arena: bool,
1782 ) Allocator.Error![:0]const u8 {
1771 const t = ty.tag();1783 const t = ty.tag();
1772 switch (t) {1784 switch (t) {
1773 .inferred_alloc_const => unreachable,1785 .inferred_alloc_const => unreachable,
...@@ -1812,71 +1824,79 @@ pub const Type = extern union {...@@ -1812,71 +1824,79 @@ pub const Type = extern union {
1812 .noreturn,1824 .noreturn,
1813 .var_args_param,1825 .var_args_param,
1814 .bound_fn,1826 .bound_fn,
1815 => return @tagName(t),1827 => return maybeDupe(@tagName(t), ally, is_arena),
18161828
1817 .enum_literal => return "@Type(.EnumLiteral)",1829 .enum_literal => return maybeDupe("@Type(.EnumLiteral)", ally, is_arena),
1818 .@"null" => return "@Type(.Null)",1830 .@"null" => return maybeDupe("@Type(.Null)", ally, is_arena),
1819 .@"undefined" => return "@Type(.Undefined)",1831 .@"undefined" => return maybeDupe("@Type(.Undefined)", ally, is_arena),
18201832
1821 .empty_struct, .empty_struct_literal => return "struct {}",1833 .empty_struct, .empty_struct_literal => return maybeDupe("struct {}", ally, is_arena),
18221834
1823 .@"struct" => {1835 .@"struct" => {
1824 const struct_obj = ty.castTag(.@"struct").?.data;1836 const struct_obj = ty.castTag(.@"struct").?.data;
1825 return try arena.dupeZ(u8, std.mem.sliceTo(struct_obj.owner_decl.name, 0));1837 return try ally.dupeZ(u8, std.mem.sliceTo(struct_obj.owner_decl.name, 0));
1826 },1838 },
1827 .@"union", .union_tagged => {1839 .@"union", .union_tagged => {
1828 const union_obj = ty.cast(Payload.Union).?.data;1840 const union_obj = ty.cast(Payload.Union).?.data;
1829 return try arena.dupeZ(u8, std.mem.sliceTo(union_obj.owner_decl.name, 0));1841 return try ally.dupeZ(u8, std.mem.sliceTo(union_obj.owner_decl.name, 0));
1830 },1842 },
1831 .enum_full, .enum_nonexhaustive => {1843 .enum_full, .enum_nonexhaustive => {
1832 const enum_full = ty.cast(Payload.EnumFull).?.data;1844 const enum_full = ty.cast(Payload.EnumFull).?.data;
1833 return try arena.dupeZ(u8, std.mem.sliceTo(enum_full.owner_decl.name, 0));1845 return try ally.dupeZ(u8, std.mem.sliceTo(enum_full.owner_decl.name, 0));
1834 },1846 },
1835 .enum_simple => {1847 .enum_simple => {
1836 const enum_simple = ty.castTag(.enum_simple).?.data;1848 const enum_simple = ty.castTag(.enum_simple).?.data;
1837 return try arena.dupeZ(u8, std.mem.sliceTo(enum_simple.owner_decl.name, 0));1849 return try ally.dupeZ(u8, std.mem.sliceTo(enum_simple.owner_decl.name, 0));
1838 },1850 },
1839 .enum_numbered => {1851 .enum_numbered => {
1840 const enum_numbered = ty.castTag(.enum_numbered).?.data;1852 const enum_numbered = ty.castTag(.enum_numbered).?.data;
1841 return try arena.dupeZ(u8, std.mem.sliceTo(enum_numbered.owner_decl.name, 0));1853 return try ally.dupeZ(u8, std.mem.sliceTo(enum_numbered.owner_decl.name, 0));
1842 },1854 },
1843 .@"opaque" => {1855 .@"opaque" => {
1844 // TODO use declaration name1856 const opaque_obj = ty.cast(Payload.Opaque).?.data;
1845 return "opaque {}";1857 return try ally.dupeZ(u8, std.mem.sliceTo(opaque_obj.owner_decl.name, 0));
1846 },1858 },
18471859
1848 .anyerror_void_error_union => return "anyerror!void",1860 .anyerror_void_error_union => return maybeDupe("anyerror!void", ally, is_arena),
1849 .const_slice_u8 => return "[]const u8",1861 .const_slice_u8 => return maybeDupe("[]const u8", ally, is_arena),
1850 .const_slice_u8_sentinel_0 => return "[:0]const u8",1862 .const_slice_u8_sentinel_0 => return maybeDupe("[:0]const u8", ally, is_arena),
1851 .fn_noreturn_no_args => return "fn() noreturn",1863 .fn_noreturn_no_args => return maybeDupe("fn() noreturn", ally, is_arena),
1852 .fn_void_no_args => return "fn() void",1864 .fn_void_no_args => return maybeDupe("fn() void", ally, is_arena),
1853 .fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn",1865 .fn_naked_noreturn_no_args => return maybeDupe("fn() callconv(.Naked) noreturn", ally, is_arena),
1854 .fn_ccc_void_no_args => return "fn() callconv(.C) void",1866 .fn_ccc_void_no_args => return maybeDupe("fn() callconv(.C) void", ally, is_arena),
1855 .single_const_pointer_to_comptime_int => return "*const comptime_int",1867 .single_const_pointer_to_comptime_int => return maybeDupe("*const comptime_int", ally, is_arena),
1856 .manyptr_u8 => return "[*]u8",1868 .manyptr_u8 => return maybeDupe("[*]u8", ally, is_arena),
1857 .manyptr_const_u8 => return "[*]const u8",1869 .manyptr_const_u8 => return maybeDupe("[*]const u8", ally, is_arena),
1858 .manyptr_const_u8_sentinel_0 => return "[*:0]const u8",1870 .manyptr_const_u8_sentinel_0 => return maybeDupe("[*:0]const u8", ally, is_arena),
1859 .atomic_order => return "AtomicOrder",1871 .atomic_order => return maybeDupe("AtomicOrder", ally, is_arena),
1860 .atomic_rmw_op => return "AtomicRmwOp",1872 .atomic_rmw_op => return maybeDupe("AtomicRmwOp", ally, is_arena),
1861 .calling_convention => return "CallingConvention",1873 .calling_convention => return maybeDupe("CallingConvention", ally, is_arena),
1862 .address_space => return "AddressSpace",1874 .address_space => return maybeDupe("AddressSpace", ally, is_arena),
1863 .float_mode => return "FloatMode",1875 .float_mode => return maybeDupe("FloatMode", ally, is_arena),
1864 .reduce_op => return "ReduceOp",1876 .reduce_op => return maybeDupe("ReduceOp", ally, is_arena),
1865 .call_options => return "CallOptions",1877 .call_options => return maybeDupe("CallOptions", ally, is_arena),
1866 .prefetch_options => return "PrefetchOptions",1878 .prefetch_options => return maybeDupe("PrefetchOptions", ally, is_arena),
1867 .export_options => return "ExportOptions",1879 .export_options => return maybeDupe("ExportOptions", ally, is_arena),
1868 .extern_options => return "ExternOptions",1880 .extern_options => return maybeDupe("ExternOptions", ally, is_arena),
1869 .type_info => return "Type",1881 .type_info => return maybeDupe("Type", ally, is_arena),
18701882
1871 else => {1883 else => {
1872 // TODO this is wasteful and also an incorrect implementation of `@typeName`1884 // TODO this is wasteful and also an incorrect implementation of `@typeName`
1873 var buf = std.ArrayList(u8).init(arena);1885 var buf = std.ArrayList(u8).init(ally);
1874 try buf.writer().print("{}", .{ty});1886 try buf.writer().print("{}", .{ty});
1875 return try buf.toOwnedSliceSentinel(0);1887 return try buf.toOwnedSliceSentinel(0);
1876 },1888 },
1877 }1889 }
1878 }1890 }
18791891
1892 fn maybeDupe(s: [:0]const u8, ally: Allocator, is_arena: bool) Allocator.Error![:0]const u8 {
1893 if (is_arena) {
1894 return s;
1895 } else {
1896 return try ally.dupeZ(u8, s);
1897 }
1898 }
1899
1880 pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {1900 pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {
1881 switch (self.tag()) {1901 switch (self.tag()) {
1882 .u1 => return Value.initTag(.u1_type),1902 .u1 => return Value.initTag(.u1_type),