From 3500b41bfed159b54b951b7cee5ff404ae5fbbda Mon Sep 17 00:00:00 2001 From: Rocknest <35231115+Rocknest@users.noreply.github.com> Date: Wed, 29 Jan 2020 16:57:43 +0200 Subject: Add an advanced segfault handler on windows --- lib/std/debug.zig | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 273 insertions(+), 5 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index d035707a54..561993fb99 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -2307,16 +2307,284 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_vo } fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.Stdcall) c_long { - const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress); switch (info.ExceptionRecord.ExceptionCode) { - windows.EXCEPTION_DATATYPE_MISALIGNMENT => panicExtra(null, exception_address, "Unaligned Memory Access", .{}), - windows.EXCEPTION_ACCESS_VIOLATION => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", .{info.ExceptionRecord.ExceptionInformation[1]}), - windows.EXCEPTION_ILLEGAL_INSTRUCTION => panicExtra(null, exception_address, "Illegal Instruction", .{}), - windows.EXCEPTION_STACK_OVERFLOW => panicExtra(null, exception_address, "Stack Overflow", .{}), + windows.EXCEPTION_DATATYPE_MISALIGNMENT => handleSegfaultWindowsExtra(info, 0, "Unaligned Memory Access"), + windows.EXCEPTION_ACCESS_VIOLATION => handleSegfaultWindowsExtra(info, 1, null), + windows.EXCEPTION_ILLEGAL_INSTRUCTION => handleSegfaultWindowsExtra(info, 2, null), + windows.EXCEPTION_STACK_OVERFLOW => handleSegfaultWindowsExtra(info, 0, "Stack Overflow"), else => return windows.EXCEPTION_CONTINUE_SEARCH, } } +// zig won't let me use an anon enum here +fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u8, comptime format: ?[]const u8) noreturn { + const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress); + if (comptime windows_exception_context.haveContext) { + const regs = windows_exception_context.getRegs(info.ContextRecord); + switch (msg) { + 0 => std.debug.warn("{}\n", .{format.?}), + 1 => std.debug.warn("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), + 2 => std.debug.warn("Illegal instruction at address 0x{x}\n", .{regs.ip}), + else => unreachable, + } + + dumpStackTraceFromBase(regs.bp, regs.ip); + os.abort(); + } else { + switch (msg) { + 0 => panicExtra(null, exception_address, format.?, .{}), + 1 => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", .{info.ExceptionRecord.ExceptionInformation[1]}), + 2 => panicExtra(null, exception_address, "Illegal Instruction", .{}), + else => unreachable, + } + } +} + +pub const windows_exception_context = switch (builtin.arch) { + .i386 => struct { + pub const haveContext = true; + + pub fn getRegs(ptr: *c_void) struct {bp: usize, ip: usize} { + const ctx = @ptrCast(*const CONTEXT, @alignCast(@alignOf(CONTEXT), ptr)); + return .{.bp = @intCast(usize, ctx.Ebp), .ip = @intCast(usize, ctx.Eip)}; + } + + pub const CONTEXT = extern struct { + ContextFlags: DWORD, + Dr0: DWORD, + Dr1: DWORD, + Dr2: DWORD, + Dr3: DWORD, + Dr6: DWORD, + Dr7: DWORD, + FloatSave: FLOATING_SAVE_AREA, + SegGs: DWORD, + SegFs: DWORD, + SegEs: DWORD, + SegDs: DWORD, + Edi: DWORD, + Esi: DWORD, + Ebx: DWORD, + Edx: DWORD, + Ecx: DWORD, + Eax: DWORD, + Ebp: DWORD, + Eip: DWORD, + SegCs: DWORD, + EFlags: DWORD, + Esp: DWORD, + SegSs: DWORD, + ExtendedRegisters: [512]BYTE, + }; + + pub const FLOATING_SAVE_AREA = extern struct { + ControlWord: DWORD, + StatusWord: DWORD, + TagWord: DWORD, + ErrorOffset: DWORD, + ErrorSelector: DWORD, + DataOffset: DWORD, + DataSelector: DWORD, + RegisterArea: [80]BYTE, + Cr0NpxState: DWORD, + }; + + pub const BYTE = u8; + pub const DWORD = c_ulong; + }, + .x86_64 => struct { + pub const haveContext = true; + + pub fn getRegs(ptr: *c_void) struct {bp: usize, ip: usize} { + const ctx = @ptrCast(*const CONTEXT, @alignCast(@alignOf(CONTEXT), ptr)); + return .{.bp = @intCast(usize, ctx.Rbp), .ip = @intCast(usize, ctx.Rip)}; + } + + pub const CONTEXT = extern struct { + P1Home: DWORD64, + P2Home: DWORD64, + P3Home: DWORD64, + P4Home: DWORD64, + P5Home: DWORD64, + P6Home: DWORD64, + ContextFlags: DWORD, + MxCsr: DWORD, + SegCs: WORD, + SegDs: WORD, + SegEs: WORD, + SegFs: WORD, + SegGs: WORD, + SegSs: WORD, + EFlags: DWORD, + Dr0: DWORD64, + Dr1: DWORD64, + Dr2: DWORD64, + Dr3: DWORD64, + Dr6: DWORD64, + Dr7: DWORD64, + Rax: DWORD64, + Rcx: DWORD64, + Rdx: DWORD64, + Rbx: DWORD64, + Rsp: DWORD64, + Rbp: DWORD64, + Rsi: DWORD64, + Rdi: DWORD64, + R8: DWORD64, + R9: DWORD64, + R10: DWORD64, + R11: DWORD64, + R12: DWORD64, + R13: DWORD64, + R14: DWORD64, + R15: DWORD64, + Rip: DWORD64, + DUMMYUNIONNAME: extern union { + FltSave: XMM_SAVE_AREA32, + FloatSave: XMM_SAVE_AREA32, + DUMMYSTRUCTNAME: extern struct { + Header: [2]M128A, + Legacy: [8]M128A, + Xmm0: M128A, + Xmm1: M128A, + Xmm2: M128A, + Xmm3: M128A, + Xmm4: M128A, + Xmm5: M128A, + Xmm6: M128A, + Xmm7: M128A, + Xmm8: M128A, + Xmm9: M128A, + Xmm10: M128A, + Xmm11: M128A, + Xmm12: M128A, + Xmm13: M128A, + Xmm14: M128A, + Xmm15: M128A, + }, + }, + VectorRegister: [26]M128A, + VectorControl: DWORD64, + DebugControl: DWORD64, + LastBranchToRip: DWORD64, + LastBranchFromRip: DWORD64, + LastExceptionToRip: DWORD64, + LastExceptionFromRip: DWORD64, + }; + + pub const XMM_SAVE_AREA32 = extern struct { + ControlWord: WORD, + StatusWord: WORD, + TagWord: BYTE, + Reserved1: BYTE, + ErrorOpcode: WORD, + ErrorOffset: DWORD, + ErrorSelector: WORD, + Reserved2: WORD, + DataOffset: DWORD, + DataSelector: WORD, + Reserved3: WORD, + MxCsr: DWORD, + MxCsr_Mask: DWORD, + FloatRegisters: [8]M128A, + XmmRegisters: [16]M128A, + Reserved4: [96]BYTE, + }; + + pub const M128A = extern struct { + Low: ULONGLONG, + High: LONGLONG, + }; + + pub const BYTE = u8; + pub const WORD = u16; + pub const DWORD = u32; + pub const DWORD64 = u64; + pub const LONGLONG = c_longlong; + pub const ULONGLONG = c_ulonglong; + }, + .aarch64 => struct { + pub const haveContext = true; + + pub fn getRegs(ptr: *c_void) struct {bp: usize, ip: usize} { + const ctx = @ptrCast(*const CONTEXT, @alignCast(@alignOf(CONTEXT), ptr)); + return .{.bp = @intCast(usize, ctx.Fp), .ip = @intCast(usize, ctx.Pc)}; + } + + pub const CONTEXT = extern struct { + ContextFlags: ULONG, + Cpsr: ULONG, + DUMMYUNIONNAME: extern union { + DUMMYSTRUCTNAME: extern struct { + X0: DWORD64, + X1: DWORD64, + X2: DWORD64, + X3: DWORD64, + X4: DWORD64, + X5: DWORD64, + X6: DWORD64, + X7: DWORD64, + X8: DWORD64, + X9: DWORD64, + X10: DWORD64, + X11: DWORD64, + X12: DWORD64, + X13: DWORD64, + X14: DWORD64, + X15: DWORD64, + X16: DWORD64, + X17: DWORD64, + X18: DWORD64, + X19: DWORD64, + X20: DWORD64, + X21: DWORD64, + X22: DWORD64, + X23: DWORD64, + X24: DWORD64, + X25: DWORD64, + X26: DWORD64, + X27: DWORD64, + X28: DWORD64, + Fp: DWORD64, + Lr: DWORD64, + }, + X: [31]DWORD64, + }, + Sp: DWORD64, + Pc: DWORD64, + V: [32]NEON128, + Fpcr: DWORD, + Fpsr: DWORD, + Bcr: [8]DWORD, + Bvr: [8]DWORD64, + Wcr: [2]DWORD, + Wvr: [2]DWORD64, + }; + + pub const NEON128 = extern union { + DUMMYSTRUCTNAME: extern struct { + Low: ULONGLONG, + High: LONGLONG, + }, + D: [2]f64, + S: [4]f32, + H: [8]WORD, + B: [16]BYTE, + }; + + pub const ULONG = c_ulong; + pub const LONGLONG = c_longlong; + pub const ULONGLONG = c_ulonglong; + pub const BYTE = u8; + pub const WORD = c_ushort; + pub const DWORD = c_ulong; + pub const DWORD64 = c_ulonglong; + }, + else => struct { + pub const haveContext = false; + }, +}; + pub fn dumpStackPointerAddr(prefix: []const u8) void { const sp = asm ("" : [argc] "={rsp}" (-> usize) -- cgit v1.2.3 From 4d134a01f5a8baae346783f19d9b5db8c8256d32 Mon Sep 17 00:00:00 2001 From: Benjamin Feng Date: Wed, 29 Jan 2020 12:21:29 -0600 Subject: Move debug.global_allocator to testing.allocator --- doc/docgen.zig | 2 +- lib/std/array_list.zig | 14 +++++----- lib/std/buffer.zig | 6 ++--- lib/std/debug.zig | 7 ++--- lib/std/fifo.zig | 4 +-- lib/std/fmt.zig | 10 +++---- lib/std/fs/path.zig | 16 +++++------ lib/std/heap.zig | 4 +++ lib/std/linked_list.zig | 6 ++--- lib/std/os/test.zig | 2 +- lib/std/priority_queue.zig | 38 +++++++++++++-------------- lib/std/process.zig | 8 +++--- lib/std/special/test_runner.zig | 1 + lib/std/testing.zig | 5 ++++ lib/std/unicode.zig | 12 ++++----- lib/std/zig/ast.zig | 2 +- test/compare_output.zig | 4 +-- test/compile_errors.zig | 2 +- test/stage1/behavior/const_slice_child.zig | 2 +- test/standalone/brace_expansion/main.zig | 4 +-- test/standalone/cat/main.zig | 2 +- test/standalone/empty_env/main.zig | 2 +- test/standalone/load_dynamic_library/main.zig | 4 +-- 23 files changed, 84 insertions(+), 73 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/doc/docgen.zig b/doc/docgen.zig index 0218f50419..678eb26043 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -672,7 +672,7 @@ const TermState = enum { test "term color" { const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; - const result = try termColor(std.debug.global_allocator, input_bytes); + const result = try termColor(std.testing.allocator, input_bytes); testing.expectEqualSlices(u8, "AgreenB", result); } diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index 64f13eff9b..be99a54e2b 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -320,7 +320,7 @@ test "std.ArrayList.basic" { } test "std.ArrayList.orderedRemove" { - var list = ArrayList(i32).init(debug.global_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); try list.append(1); @@ -347,7 +347,7 @@ test "std.ArrayList.orderedRemove" { } test "std.ArrayList.swapRemove" { - var list = ArrayList(i32).init(debug.global_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); try list.append(1); @@ -374,7 +374,7 @@ test "std.ArrayList.swapRemove" { } test "std.ArrayList.swapRemoveOrError" { - var list = ArrayList(i32).init(debug.global_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); // Test just after initialization @@ -402,7 +402,7 @@ test "std.ArrayList.swapRemoveOrError" { } test "std.ArrayList.insert" { - var list = ArrayList(i32).init(debug.global_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); try list.append(1); @@ -416,7 +416,7 @@ test "std.ArrayList.insert" { } test "std.ArrayList.insertSlice" { - var list = ArrayList(i32).init(debug.global_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); try list.append(1); @@ -443,7 +443,7 @@ const Item = struct { }; test "std.ArrayList: ArrayList(T) of struct T" { - var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) }; - try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) }); + var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(testing.allocator) }; + try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(testing.allocator) }); testing.expect(root.sub_items.items[0].integer == 42); } diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig index 42bf8e8142..ada3590616 100644 --- a/lib/std/buffer.zig +++ b/lib/std/buffer.zig @@ -150,7 +150,7 @@ pub const Buffer = struct { }; test "simple Buffer" { - var buf = try Buffer.init(debug.global_allocator, ""); + var buf = try Buffer.init(testing.allocator, ""); testing.expect(buf.len() == 0); try buf.append("hello"); try buf.append(" "); @@ -169,14 +169,14 @@ test "simple Buffer" { } test "Buffer.initSize" { - var buf = try Buffer.initSize(debug.global_allocator, 3); + var buf = try Buffer.initSize(testing.allocator, 3); testing.expect(buf.len() == 3); try buf.append("hello"); testing.expect(mem.eql(u8, buf.toSliceConst()[3..], "hello")); } test "Buffer.initCapacity" { - var buf = try Buffer.initCapacity(debug.global_allocator, 10); + var buf = try Buffer.initCapacity(testing.allocator, 10); testing.expect(buf.len() == 0); testing.expect(buf.capacity() >= 10); const old_cap = buf.capacity(); diff --git a/lib/std/debug.zig b/lib/std/debug.zig index d035707a54..f2dcdd7e77 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -20,7 +20,7 @@ const windows = std.os.windows; pub const leb = @import("debug/leb128.zig"); pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator; -pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator; +pub const failing_allocator = &FailingAllocator.init(&global_fixed_allocator.allocator, 0).allocator; pub const runtime_safety = switch (builtin.mode) { .Debug, .ReleaseSafe => true, @@ -2192,8 +2192,9 @@ fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) } } -/// This should only be used in temporary test programs. -pub const global_allocator = &global_fixed_allocator.allocator; +pub const global_allocator = blk: { + @compileError("Please switch to std.testing.allocator."); +}; var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]); var global_allocator_mem: [100 * 1024]u8 = undefined; diff --git a/lib/std/fifo.zig b/lib/std/fifo.zig index 7870979abb..ac8589f2ce 100644 --- a/lib/std/fifo.zig +++ b/lib/std/fifo.zig @@ -347,7 +347,7 @@ pub fn LinearFifo( } test "LinearFifo(u8, .Dynamic)" { - var fifo = LinearFifo(u8, .Dynamic).init(debug.global_allocator); + var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); defer fifo.deinit(); try fifo.write("HELLO"); @@ -422,7 +422,7 @@ test "LinearFifo" { var fifo = switch (bt) { .Static => FifoType.init(), .Slice => FifoType.init(buf[0..]), - .Dynamic => FifoType.init(debug.global_allocator), + .Dynamic => FifoType.init(testing.allocator), }; defer fifo.deinit(); diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index cf3322a995..9757658447 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1598,7 +1598,7 @@ test "hexToBytes" { test "formatIntValue with comptime_int" { const value: comptime_int = 123456789123456789; - var buf = try std.Buffer.init(std.debug.global_allocator, ""); + var buf = try std.Buffer.init(std.testing.allocator, ""); try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append); std.testing.expect(mem.eql(u8, buf.toSlice(), "123456789123456789")); } @@ -1652,19 +1652,19 @@ test "formatType max_depth" { inst.a = &inst; inst.tu.ptr = &inst.tu; - var buf0 = try std.Buffer.init(std.debug.global_allocator, ""); + var buf0 = try std.Buffer.init(std.testing.allocator, ""); try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0); std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }")); - var buf1 = try std.Buffer.init(std.debug.global_allocator, ""); + var buf1 = try std.Buffer.init(std.testing.allocator, ""); try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1); std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }")); - var buf2 = try std.Buffer.init(std.debug.global_allocator, ""); + var buf2 = try std.Buffer.init(std.testing.allocator, ""); try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2); std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }")); - var buf3 = try std.Buffer.init(std.debug.global_allocator, ""); + var buf3 = try std.Buffer.init(std.testing.allocator, ""); try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3); std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }")); } diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index b3ad3e9f7a..6c29a3950c 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -665,7 +665,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { } test "resolve" { - const cwd = try process.getCwdAlloc(debug.global_allocator); + const cwd = try process.getCwdAlloc(testing.allocator); if (builtin.os == .windows) { if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { cwd[0] = asciiUpper(cwd[0]); @@ -683,11 +683,11 @@ test "resolveWindows" { return error.SkipZigTest; } if (builtin.os == .windows) { - const cwd = try process.getCwdAlloc(debug.global_allocator); + const cwd = try process.getCwdAlloc(testing.allocator); const parsed_cwd = windowsParsePath(cwd); { const result = testResolveWindows(&[_][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" }); - const expected = try join(debug.global_allocator, &[_][]const u8{ + const expected = try join(testing.allocator, &[_][]const u8{ parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig", }); @@ -698,7 +698,7 @@ test "resolveWindows" { } { const result = testResolveWindows(&[_][]const u8{ "usr/local", "lib\\zig" }); - const expected = try join(debug.global_allocator, &[_][]const u8{ + const expected = try join(testing.allocator, &[_][]const u8{ cwd, "usr\\local\\lib\\zig", }); @@ -738,11 +738,11 @@ test "resolvePosix" { } fn testResolveWindows(paths: []const []const u8) []u8 { - return resolveWindows(debug.global_allocator, paths) catch unreachable; + return resolveWindows(testing.allocator, paths) catch unreachable; } fn testResolvePosix(paths: []const []const u8) []u8 { - return resolvePosix(debug.global_allocator, paths) catch unreachable; + return resolvePosix(testing.allocator, paths) catch unreachable; } /// If the path is a file in the current directory (no directory component) @@ -1166,11 +1166,11 @@ test "relative" { } fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) void { - const result = relativePosix(debug.global_allocator, from, to) catch unreachable; + const result = relativePosix(testing.allocator, from, to) catch unreachable; testing.expectEqualSlices(u8, expected_output, result); } fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) void { - const result = relativeWindows(debug.global_allocator, from, to) catch unreachable; + const result = relativeWindows(testing.allocator, from, to) catch unreachable; testing.expectEqualSlices(u8, expected_output, result); } diff --git a/lib/std/heap.zig b/lib/std/heap.zig index f25d2f0172..e7196f82f2 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -711,6 +711,10 @@ pub const ThreadSafeFixedBufferAllocator = blk: { fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { return old_mem[0..new_size]; } + + pub fn reset(self: *ThreadSafeFixedBufferAllocator) void { + self.end_index = 0; + } }; } }; diff --git a/lib/std/linked_list.zig b/lib/std/linked_list.zig index 6495653150..a21c9a83eb 100644 --- a/lib/std/linked_list.zig +++ b/lib/std/linked_list.zig @@ -143,7 +143,7 @@ pub fn SinglyLinkedList(comptime T: type) type { } test "basic SinglyLinkedList test" { - const allocator = debug.global_allocator; + const allocator = testing.allocator; var list = SinglyLinkedList(u32).init(); var one = try list.createNode(1, allocator); @@ -404,7 +404,7 @@ pub fn TailQueue(comptime T: type) type { } test "basic TailQueue test" { - const allocator = debug.global_allocator; + const allocator = testing.allocator; var list = TailQueue(u32).init(); var one = try list.createNode(1, allocator); @@ -456,7 +456,7 @@ test "basic TailQueue test" { } test "TailQueue concatenation" { - const allocator = debug.global_allocator; + const allocator = testing.allocator; var list1 = TailQueue(u32).init(); var list2 = TailQueue(u32).init(); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index f71e80c7d7..0d3be9e7e4 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -9,7 +9,7 @@ const elf = std.elf; const File = std.fs.File; const Thread = std.Thread; -const a = std.debug.global_allocator; +const a = std.testing.allocator; const builtin = @import("builtin"); const AtomicRmwOp = builtin.AtomicRmwOp; diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig index 6c56f469f9..e726a07a88 100644 --- a/lib/std/priority_queue.zig +++ b/lib/std/priority_queue.zig @@ -1,10 +1,10 @@ const std = @import("std.zig"); const Allocator = std.mem.Allocator; -const debug = std.debug; -const assert = debug.assert; -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; -const expectError = std.testing.expectError; +const assert = std.debug.assert; +const testing = std.testing; +const expect = testing.expect; +const expectEqual = testing.expectEqual; +const expectError = testing.expectError; /// Priority queue for storing generic data. Initialize with `init`. pub fn PriorityQueue(comptime T: type) type { @@ -239,7 +239,7 @@ fn greaterThan(a: u32, b: u32) bool { const PQ = PriorityQueue(u32); test "std.PriorityQueue: add and remove min heap" { - var queue = PQ.init(debug.global_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); try queue.add(54); @@ -257,7 +257,7 @@ test "std.PriorityQueue: add and remove min heap" { } test "std.PriorityQueue: add and remove same min heap" { - var queue = PQ.init(debug.global_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); try queue.add(1); @@ -275,14 +275,14 @@ test "std.PriorityQueue: add and remove same min heap" { } test "std.PriorityQueue: removeOrNull on empty" { - var queue = PQ.init(debug.global_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); expect(queue.removeOrNull() == null); } test "std.PriorityQueue: edge case 3 elements" { - var queue = PQ.init(debug.global_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); try queue.add(9); @@ -294,7 +294,7 @@ test "std.PriorityQueue: edge case 3 elements" { } test "std.PriorityQueue: peek" { - var queue = PQ.init(debug.global_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); expect(queue.peek() == null); @@ -306,7 +306,7 @@ test "std.PriorityQueue: peek" { } test "std.PriorityQueue: sift up with odd indices" { - var queue = PQ.init(debug.global_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; for (items) |e| { @@ -320,7 +320,7 @@ test "std.PriorityQueue: sift up with odd indices" { } test "std.PriorityQueue: addSlice" { - var queue = PQ.init(debug.global_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; try queue.addSlice(items[0..]); @@ -333,8 +333,8 @@ test "std.PriorityQueue: addSlice" { test "std.PriorityQueue: fromOwnedSlice" { const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; - const heap_items = try std.mem.dupe(debug.global_allocator, u32, items[0..]); - var queue = PQ.fromOwnedSlice(debug.global_allocator, lessThan, heap_items[0..]); + const heap_items = try std.mem.dupe(testing.allocator, u32, items[0..]); + var queue = PQ.fromOwnedSlice(testing.allocator, lessThan, heap_items[0..]); defer queue.deinit(); const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 }; @@ -344,7 +344,7 @@ test "std.PriorityQueue: fromOwnedSlice" { } test "std.PriorityQueue: add and remove max heap" { - var queue = PQ.init(debug.global_allocator, greaterThan); + var queue = PQ.init(testing.allocator, greaterThan); defer queue.deinit(); try queue.add(54); @@ -362,7 +362,7 @@ test "std.PriorityQueue: add and remove max heap" { } test "std.PriorityQueue: add and remove same max heap" { - var queue = PQ.init(debug.global_allocator, greaterThan); + var queue = PQ.init(testing.allocator, greaterThan); defer queue.deinit(); try queue.add(1); @@ -380,8 +380,8 @@ test "std.PriorityQueue: add and remove same max heap" { } test "std.PriorityQueue: iterator" { - var queue = PQ.init(debug.global_allocator, lessThan); - var map = std.AutoHashMap(u32, void).init(debug.global_allocator); + var queue = PQ.init(testing.allocator, lessThan); + var map = std.AutoHashMap(u32, void).init(testing.allocator); defer { queue.deinit(); map.deinit(); @@ -402,7 +402,7 @@ test "std.PriorityQueue: iterator" { } test "std.PriorityQueue: remove at index" { - var queue = PQ.init(debug.global_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); try queue.add(3); diff --git a/lib/std/process.zig b/lib/std/process.zig index 0ce3cabc19..2758e25ac0 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -114,7 +114,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { } test "os.getEnvMap" { - var env = try getEnvMap(std.debug.global_allocator); + var env = try getEnvMap(std.testing.allocator); defer env.deinit(); } @@ -165,7 +165,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } test "os.getEnvVarOwned" { - var ga = std.debug.global_allocator; + var ga = std.testing.allocator; testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV")); } @@ -492,10 +492,10 @@ test "windows arg parsing" { fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void { var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line); for (expected_args) |expected_arg| { - const arg = it.next(std.debug.global_allocator).? catch unreachable; + const arg = it.next(std.testing.allocator).? catch unreachable; testing.expectEqualSlices(u8, expected_arg, arg); } - testing.expect(it.next(std.debug.global_allocator) == null); + testing.expect(it.next(std.testing.allocator) == null); } pub const UserInfo = struct { diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index 0335c8562d..286dfbed1b 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -13,6 +13,7 @@ pub fn main() anyerror!void { }; for (test_fn_list) |test_fn, i| { + std.testing.allocator_instance.reset(); var test_node = root_node.start(test_fn.name, null); test_node.activate(); progress.refresh(); diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 7a261e0751..02d7cdb393 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -2,6 +2,11 @@ const builtin = @import("builtin"); const TypeId = builtin.TypeId; const std = @import("std.zig"); +/// This should only be used in temporary test programs. +pub const allocator = &allocator_instance.allocator; +pub var allocator_instance = std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..]); +var allocator_mem: [100 * 1024]u8 = undefined; + /// This function is intended to be used only in tests. It prints diagnostics to stderr /// and then aborts when actual_error_union is not expected_error. pub fn expectError(expected_error: anyerror, actual_error_union: var) void { diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 3d16748447..638b5f5e2f 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -501,14 +501,14 @@ test "utf16leToUtf8" { { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); - const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); testing.expect(mem.eql(u8, utf8, "Aa")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); - const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); testing.expect(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } @@ -516,7 +516,7 @@ test "utf16leToUtf8" { // the values just outside the surrogate half range mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); - const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); testing.expect(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } @@ -524,7 +524,7 @@ test "utf16leToUtf8" { // smallest surrogate pair mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); - const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); testing.expect(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } @@ -532,14 +532,14 @@ test "utf16leToUtf8" { // largest surrogate pair mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); - const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); - const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } } diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index dc9a6bc7ca..e339343823 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -2287,7 +2287,7 @@ pub const Node = struct { test "iterate" { var root = Node.Root{ .base = Node{ .id = Node.Id.Root }, - .decls = Node.Root.DeclList.init(std.debug.global_allocator), + .decls = Node.Root.DeclList.init(std.testing.allocator), .eof_token = 0, }; var base = &root.base; diff --git a/test/compare_output.zig b/test/compare_output.zig index db20709afa..7a41d46f54 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -445,7 +445,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\const std = @import("std"); \\const io = std.io; \\const os = std.os; - \\const allocator = std.debug.global_allocator; + \\const allocator = std.testing.allocator; \\ \\pub fn main() !void { \\ var args_it = std.process.args(); @@ -486,7 +486,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\const std = @import("std"); \\const io = std.io; \\const os = std.os; - \\const allocator = std.debug.global_allocator; + \\const allocator = std.testing.allocator; \\ \\pub fn main() !void { \\ var args_it = std.process.args(); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 89e187aed2..341062e161 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5765,7 +5765,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() void { \\ const a = MdNode.Header { - \\ .text = MdText.init(&std.debug.global_allocator), + \\ .text = MdText.init(&std.testing.allocator), \\ .weight = HeaderWeight.H1, \\ }; \\} diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig index 6720667187..cf650ae88e 100644 --- a/test/stage1/behavior/const_slice_child.zig +++ b/test/stage1/behavior/const_slice_child.zig @@ -22,7 +22,7 @@ fn foo(args: [][]const u8) void { } fn bar(argc: usize) void { - const args = debug.global_allocator.alloc([]const u8, argc) catch unreachable; + const args = testing.allocator.alloc([]const u8, argc) catch unreachable; for (args) |_, i| { const ptr = argv[i]; args[i] = ptr[0..strlen(ptr)]; diff --git a/test/standalone/brace_expansion/main.zig b/test/standalone/brace_expansion/main.zig index cbb328541e..c6bfd02e79 100644 --- a/test/standalone/brace_expansion/main.zig +++ b/test/standalone/brace_expansion/main.zig @@ -201,7 +201,7 @@ pub fn main() !void { } test "invalid inputs" { - global_allocator = std.debug.global_allocator; + global_allocator = std.testing.allocator; expectError("}ABC", error.InvalidInput); expectError("{ABC", error.InvalidInput); @@ -222,7 +222,7 @@ fn expectError(test_input: []const u8, expected_err: anyerror) void { } test "valid inputs" { - global_allocator = std.debug.global_allocator; + global_allocator = std.testing.allocator; expectExpansion("{x,y,z}", "x y z"); expectExpansion("{A,B}{x,y}", "Ax Ay Bx By"); diff --git a/test/standalone/cat/main.zig b/test/standalone/cat/main.zig index f0cd9728ab..34439f9c24 100644 --- a/test/standalone/cat/main.zig +++ b/test/standalone/cat/main.zig @@ -4,7 +4,7 @@ const process = std.process; const fs = std.fs; const mem = std.mem; const warn = std.debug.warn; -const allocator = std.debug.global_allocator; +const allocator = std.testing.allocator; pub fn main() !void { var args_it = process.args(); diff --git a/test/standalone/empty_env/main.zig b/test/standalone/empty_env/main.zig index d6d5ecb5af..f4ebf56136 100644 --- a/test/standalone/empty_env/main.zig +++ b/test/standalone/empty_env/main.zig @@ -1,6 +1,6 @@ const std = @import("std"); pub fn main() void { - const env_map = std.process.getEnvMap(std.debug.global_allocator) catch @panic("unable to get env map"); + const env_map = std.process.getEnvMap(std.testing.allocator) catch @panic("unable to get env map"); std.testing.expect(env_map.count() == 0); } diff --git a/test/standalone/load_dynamic_library/main.zig b/test/standalone/load_dynamic_library/main.zig index 197e3ca47c..70fc4986ac 100644 --- a/test/standalone/load_dynamic_library/main.zig +++ b/test/standalone/load_dynamic_library/main.zig @@ -1,8 +1,8 @@ const std = @import("std"); pub fn main() !void { - const args = try std.process.argsAlloc(std.debug.global_allocator); - defer std.process.argsFree(std.debug.global_allocator, args); + const args = try std.process.argsAlloc(std.testing.allocator); + defer std.process.argsFree(std.testing.allocator, args); const dynlib_name = args[1]; -- cgit v1.2.3 From b7cd60a354731d61ee3a3184fd4be610382ca1d6 Mon Sep 17 00:00:00 2001 From: Rocknest <35231115+Rocknest@users.noreply.github.com> Date: Wed, 29 Jan 2020 21:09:00 +0200 Subject: Changing stuff and seeing what happens --- lib/std/debug.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 561993fb99..acc3f36412 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -129,7 +129,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { return; }; const tty_config = detectTTYConfig(); - printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; + printSourceAtAddress(debug_info, stderr, if (builtin.os == .windows) (ip + 1) else ip, tty_config) catch return; const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*; printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return; var it = StackIterator{ @@ -325,6 +325,7 @@ pub const StackIterator = struct { } const return_address = @intToPtr(*const usize, self.fp - fp_adjust_factor + @sizeOf(usize)).*; + if (return_address == 0) return null; return return_address; } }; -- cgit v1.2.3 From aa9caf5064b3fc01579b7bd8c765ff33323a073a Mon Sep 17 00:00:00 2001 From: Benjamin Feng Date: Wed, 29 Jan 2020 13:18:04 -0600 Subject: Create leak_count_allocator --- doc/docgen.zig | 2 +- lib/std/array_list.zig | 15 +-- lib/std/buffer.zig | 11 +- lib/std/debug.zig | 2 +- lib/std/fifo.zig | 4 +- lib/std/fmt.zig | 15 ++- lib/std/fs/path.zig | 166 ++++++++++++++------------ lib/std/linked_list.zig | 6 +- lib/std/os/test.zig | 2 +- lib/std/priority_queue.zig | 28 ++--- lib/std/process.zig | 9 +- lib/std/special/test_runner.zig | 3 + lib/std/testing.zig | 42 +++++++ lib/std/unicode.zig | 18 ++- lib/std/zig/ast.zig | 2 +- test/compare_output.zig | 4 +- test/compile_errors.zig | 2 +- test/stage1/behavior/const_slice_child.zig | 2 +- test/standalone/brace_expansion/main.zig | 4 +- test/standalone/cat/main.zig | 2 +- test/standalone/empty_env/main.zig | 2 +- test/standalone/load_dynamic_library/main.zig | 4 +- 22 files changed, 208 insertions(+), 137 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/doc/docgen.zig b/doc/docgen.zig index 678eb26043..128314696e 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -672,7 +672,7 @@ const TermState = enum { test "term color" { const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; - const result = try termColor(std.testing.allocator, input_bytes); + const result = try termColor(std.testing.leak_count_allocator, input_bytes); testing.expectEqualSlices(u8, "AgreenB", result); } diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index be99a54e2b..57c0d706a2 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -320,7 +320,7 @@ test "std.ArrayList.basic" { } test "std.ArrayList.orderedRemove" { - var list = ArrayList(i32).init(testing.allocator); + var list = ArrayList(i32).init(testing.leak_count_allocator); defer list.deinit(); try list.append(1); @@ -347,7 +347,7 @@ test "std.ArrayList.orderedRemove" { } test "std.ArrayList.swapRemove" { - var list = ArrayList(i32).init(testing.allocator); + var list = ArrayList(i32).init(testing.leak_count_allocator); defer list.deinit(); try list.append(1); @@ -374,7 +374,7 @@ test "std.ArrayList.swapRemove" { } test "std.ArrayList.swapRemoveOrError" { - var list = ArrayList(i32).init(testing.allocator); + var list = ArrayList(i32).init(testing.leak_count_allocator); defer list.deinit(); // Test just after initialization @@ -402,7 +402,7 @@ test "std.ArrayList.swapRemoveOrError" { } test "std.ArrayList.insert" { - var list = ArrayList(i32).init(testing.allocator); + var list = ArrayList(i32).init(testing.leak_count_allocator); defer list.deinit(); try list.append(1); @@ -416,7 +416,7 @@ test "std.ArrayList.insert" { } test "std.ArrayList.insertSlice" { - var list = ArrayList(i32).init(testing.allocator); + var list = ArrayList(i32).init(testing.leak_count_allocator); defer list.deinit(); try list.append(1); @@ -443,7 +443,8 @@ const Item = struct { }; test "std.ArrayList: ArrayList(T) of struct T" { - var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(testing.allocator) }; - try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(testing.allocator) }); + var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(testing.leak_count_allocator) }; + defer root.sub_items.deinit(); + try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(testing.leak_count_allocator) }); testing.expect(root.sub_items.items[0].integer == 42); } diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig index ada3590616..cc1166e0e7 100644 --- a/lib/std/buffer.zig +++ b/lib/std/buffer.zig @@ -150,7 +150,9 @@ pub const Buffer = struct { }; test "simple Buffer" { - var buf = try Buffer.init(testing.allocator, ""); + var buf = try Buffer.init(testing.leak_count_allocator, ""); + defer buf.deinit(); + testing.expect(buf.len() == 0); try buf.append("hello"); try buf.append(" "); @@ -159,6 +161,7 @@ test "simple Buffer" { testing.expect(mem.eql(u8, mem.toSliceConst(u8, buf.toSliceConst().ptr), buf.toSliceConst())); var buf2 = try Buffer.initFromBuffer(buf); + defer buf2.deinit(); testing.expect(buf.eql(buf2.toSliceConst())); testing.expect(buf.startsWith("hell")); @@ -169,14 +172,16 @@ test "simple Buffer" { } test "Buffer.initSize" { - var buf = try Buffer.initSize(testing.allocator, 3); + var buf = try Buffer.initSize(testing.leak_count_allocator, 3); + defer buf.deinit(); testing.expect(buf.len() == 3); try buf.append("hello"); testing.expect(mem.eql(u8, buf.toSliceConst()[3..], "hello")); } test "Buffer.initCapacity" { - var buf = try Buffer.initCapacity(testing.allocator, 10); + var buf = try Buffer.initCapacity(testing.leak_count_allocator, 10); + defer buf.deinit(); testing.expect(buf.len() == 0); testing.expect(buf.capacity() >= 10); const old_cap = buf.capacity(); diff --git a/lib/std/debug.zig b/lib/std/debug.zig index f2dcdd7e77..7e1a99a395 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -2193,7 +2193,7 @@ fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) } pub const global_allocator = blk: { - @compileError("Please switch to std.testing.allocator."); + @compileError("Please switch to std.testing.leak_count_allocator."); }; var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]); var global_allocator_mem: [100 * 1024]u8 = undefined; diff --git a/lib/std/fifo.zig b/lib/std/fifo.zig index ac8589f2ce..dd429289d1 100644 --- a/lib/std/fifo.zig +++ b/lib/std/fifo.zig @@ -347,7 +347,7 @@ pub fn LinearFifo( } test "LinearFifo(u8, .Dynamic)" { - var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); + var fifo = LinearFifo(u8, .Dynamic).init(testing.leak_count_allocator); defer fifo.deinit(); try fifo.write("HELLO"); @@ -422,7 +422,7 @@ test "LinearFifo" { var fifo = switch (bt) { .Static => FifoType.init(), .Slice => FifoType.init(buf[0..]), - .Dynamic => FifoType.init(testing.allocator), + .Dynamic => FifoType.init(testing.leak_count_allocator), }; defer fifo.deinit(); diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 9757658447..529131065c 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1598,7 +1598,8 @@ test "hexToBytes" { test "formatIntValue with comptime_int" { const value: comptime_int = 123456789123456789; - var buf = try std.Buffer.init(std.testing.allocator, ""); + var buf = try std.Buffer.init(std.testing.leak_count_allocator, ""); + defer buf.deinit(); try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append); std.testing.expect(mem.eql(u8, buf.toSlice(), "123456789123456789")); } @@ -1652,19 +1653,23 @@ test "formatType max_depth" { inst.a = &inst; inst.tu.ptr = &inst.tu; - var buf0 = try std.Buffer.init(std.testing.allocator, ""); + var buf0 = try std.Buffer.init(std.testing.leak_count_allocator, ""); + defer buf0.deinit(); try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0); std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }")); - var buf1 = try std.Buffer.init(std.testing.allocator, ""); + var buf1 = try std.Buffer.init(std.testing.leak_count_allocator, ""); + defer buf1.deinit(); try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1); std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }")); - var buf2 = try std.Buffer.init(std.testing.allocator, ""); + var buf2 = try std.Buffer.init(std.testing.leak_count_allocator, ""); + defer buf2.deinit(); try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2); std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }")); - var buf3 = try std.Buffer.init(std.testing.allocator, ""); + var buf3 = try std.Buffer.init(std.testing.leak_count_allocator, ""); + defer buf3.deinit(); try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3); std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }")); } diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 6c29a3950c..424e9f5759 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -665,15 +665,16 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { } test "resolve" { - const cwd = try process.getCwdAlloc(testing.allocator); + const cwd = try process.getCwdAlloc(testing.leak_count_allocator); + defer testing.leak_count_allocator.free(cwd); if (builtin.os == .windows) { if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { cwd[0] = asciiUpper(cwd[0]); } - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{"."}), cwd)); + try testResolveWindows(&[_][]const u8{"."}, cwd); } else { - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "a/b/c/", "../../.." }), cwd)); - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{"."}), cwd)); + try testResolvePosix(&[_][]const u8{ "a/b/c/", "../../.." }, cwd); + try testResolvePosix(&[_][]const u8{"."}, cwd); } } @@ -683,66 +684,71 @@ test "resolveWindows" { return error.SkipZigTest; } if (builtin.os == .windows) { - const cwd = try process.getCwdAlloc(testing.allocator); + const cwd = try process.getCwdAlloc(testing.leak_count_allocator); + defer testing.leak_count_allocator.free(cwd); const parsed_cwd = windowsParsePath(cwd); { - const result = testResolveWindows(&[_][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" }); - const expected = try join(testing.allocator, &[_][]const u8{ + const expected = try join(testing.leak_count_allocator, &[_][]const u8{ parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig", }); + defer testing.leak_count_allocator.free(expected); if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } - testing.expect(mem.eql(u8, result, expected)); + try testResolveWindows(&[_][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" }, expected); } { - const result = testResolveWindows(&[_][]const u8{ "usr/local", "lib\\zig" }); - const expected = try join(testing.allocator, &[_][]const u8{ + const expected = try join(testing.leak_count_allocator, &[_][]const u8{ cwd, "usr\\local\\lib\\zig", }); + defer testing.leak_count_allocator.free(expected); if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } - testing.expect(mem.eql(u8, result, expected)); + try testResolveWindows(&[_][]const u8{ "usr/local", "lib\\zig" }, expected); } } - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }), "C:\\hi\\ok")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }), "C:\\blah\\a")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }), "C:\\blah\\a")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }), "D:\\e.exe")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/ignore", "c:/some/file" }), "C:\\some\\file")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "d:/ignore", "d:some/dir//" }), "D:\\ignore\\some\\dir")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "//server/share", "..", "relative\\" }), "\\\\server\\share\\relative")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/", "//" }), "C:\\")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/", "//dir" }), "C:\\dir")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/", "//server/share" }), "\\\\server\\share\\")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/", "//server//share" }), "\\\\server\\share\\")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "c:/", "///some//dir" }), "C:\\some\\dir")); - testing.expect(mem.eql(u8, testResolveWindows(&[_][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js")); + try testResolveWindows(&[_][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }, "C:\\hi\\ok"); + try testResolveWindows(&[_][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }, "C:\\blah\\a"); + try testResolveWindows(&[_][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }, "C:\\blah\\a"); + try testResolveWindows(&[_][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }, "D:\\e.exe"); + try testResolveWindows(&[_][]const u8{ "c:/ignore", "c:/some/file" }, "C:\\some\\file"); + try testResolveWindows(&[_][]const u8{ "d:/ignore", "d:some/dir//" }, "D:\\ignore\\some\\dir"); + try testResolveWindows(&[_][]const u8{ "//server/share", "..", "relative\\" }, "\\\\server\\share\\relative"); + try testResolveWindows(&[_][]const u8{ "c:/", "//" }, "C:\\"); + try testResolveWindows(&[_][]const u8{ "c:/", "//dir" }, "C:\\dir"); + try testResolveWindows(&[_][]const u8{ "c:/", "//server/share" }, "\\\\server\\share\\"); + try testResolveWindows(&[_][]const u8{ "c:/", "//server//share" }, "\\\\server\\share\\"); + try testResolveWindows(&[_][]const u8{ "c:/", "///some//dir" }, "C:\\some\\dir"); + try testResolveWindows(&[_][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }, "C:\\foo\\tmp.3\\cycles\\root.js"); } test "resolvePosix" { - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "/a/b", "c" }), "/a/b/c")); - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e")); - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "/a/b/c", "..", "../" }), "/a")); - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "/", "..", ".." }), "/")); - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{"/a/b/c/"}), "/a/b/c")); - - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "/var/lib", "../", "file/" }), "/var/file")); - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "/var/lib", "/../", "file/" }), "/file")); - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "/some/dir", ".", "/absolute/" }), "/absolute")); - testing.expect(mem.eql(u8, testResolvePosix(&[_][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }), "/foo/tmp.3/cycles/root.js")); + try testResolvePosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c"); + try testResolvePosix(&[_][]const u8{ "/a/b", "c", "//d", "e///" }, "/d/e"); + try testResolvePosix(&[_][]const u8{ "/a/b/c", "..", "../" }, "/a"); + try testResolvePosix(&[_][]const u8{ "/", "..", ".." }, "/"); + try testResolvePosix(&[_][]const u8{"/a/b/c/"}, "/a/b/c"); + + try testResolvePosix(&[_][]const u8{ "/var/lib", "../", "file/" }, "/var/file"); + try testResolvePosix(&[_][]const u8{ "/var/lib", "/../", "file/" }, "/file"); + try testResolvePosix(&[_][]const u8{ "/some/dir", ".", "/absolute/" }, "/absolute"); + try testResolvePosix(&[_][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }, "/foo/tmp.3/cycles/root.js"); } -fn testResolveWindows(paths: []const []const u8) []u8 { - return resolveWindows(testing.allocator, paths) catch unreachable; +fn testResolveWindows(paths: []const []const u8, expected: []const u8) !void { + const actual = try resolveWindows(testing.leak_count_allocator, paths); + defer testing.leak_count_allocator.free(actual); + return testing.expect(mem.eql(u8, actual, expected)); } -fn testResolvePosix(paths: []const []const u8) []u8 { - return resolvePosix(testing.allocator, paths) catch unreachable; +fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void { + const actual = try resolvePosix(testing.leak_count_allocator, paths); + defer testing.leak_count_allocator.free(actual); + return testing.expect(mem.eql(u8, actual, expected)); } /// If the path is a file in the current directory (no directory component) @@ -1126,51 +1132,53 @@ test "relative" { // TODO https://github.com/ziglang/zig/issues/3288 return error.SkipZigTest; } - testRelativeWindows("c:/blah\\blah", "d:/games", "D:\\games"); - testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa", ".."); - testRelativeWindows("c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc"); - testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa/bbbb", ""); - testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa/cccc", "..\\cccc"); - testRelativeWindows("c:/aaaa/", "c:/aaaa/cccc", "cccc"); - testRelativeWindows("c:/", "c:\\aaaa\\bbbb", "aaaa\\bbbb"); - testRelativeWindows("c:/aaaa/bbbb", "d:\\", "D:\\"); - testRelativeWindows("c:/AaAa/bbbb", "c:/aaaa/bbbb", ""); - testRelativeWindows("c:/aaaaa/", "c:/aaaa/cccc", "..\\aaaa\\cccc"); - testRelativeWindows("C:\\foo\\bar\\baz\\quux", "C:\\", "..\\..\\..\\.."); - testRelativeWindows("C:\\foo\\test", "C:\\foo\\test\\bar\\package.json", "bar\\package.json"); - testRelativeWindows("C:\\foo\\bar\\baz-quux", "C:\\foo\\bar\\baz", "..\\baz"); - testRelativeWindows("C:\\foo\\bar\\baz", "C:\\foo\\bar\\baz-quux", "..\\baz-quux"); - testRelativeWindows("\\\\foo\\bar", "\\\\foo\\bar\\baz", "baz"); - testRelativeWindows("\\\\foo\\bar\\baz", "\\\\foo\\bar", ".."); - testRelativeWindows("\\\\foo\\bar\\baz-quux", "\\\\foo\\bar\\baz", "..\\baz"); - testRelativeWindows("\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz-quux", "..\\baz-quux"); - testRelativeWindows("C:\\baz-quux", "C:\\baz", "..\\baz"); - testRelativeWindows("C:\\baz", "C:\\baz-quux", "..\\baz-quux"); - testRelativeWindows("\\\\foo\\baz-quux", "\\\\foo\\baz", "..\\baz"); - testRelativeWindows("\\\\foo\\baz", "\\\\foo\\baz-quux", "..\\baz-quux"); - testRelativeWindows("C:\\baz", "\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz"); - testRelativeWindows("\\\\foo\\bar\\baz", "C:\\baz", "C:\\baz"); - - testRelativePosix("/var/lib", "/var", ".."); - testRelativePosix("/var/lib", "/bin", "../../bin"); - testRelativePosix("/var/lib", "/var/lib", ""); - testRelativePosix("/var/lib", "/var/apache", "../apache"); - testRelativePosix("/var/", "/var/lib", "lib"); - testRelativePosix("/", "/var/lib", "var/lib"); - testRelativePosix("/foo/test", "/foo/test/bar/package.json", "bar/package.json"); - testRelativePosix("/Users/a/web/b/test/mails", "/Users/a/web/b", "../.."); - testRelativePosix("/foo/bar/baz-quux", "/foo/bar/baz", "../baz"); - testRelativePosix("/foo/bar/baz", "/foo/bar/baz-quux", "../baz-quux"); - testRelativePosix("/baz-quux", "/baz", "../baz"); - testRelativePosix("/baz", "/baz-quux", "../baz-quux"); + try testRelativeWindows("c:/blah\\blah", "d:/games", "D:\\games"); + try testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa", ".."); + try testRelativeWindows("c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc"); + try testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa/bbbb", ""); + try testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa/cccc", "..\\cccc"); + try testRelativeWindows("c:/aaaa/", "c:/aaaa/cccc", "cccc"); + try testRelativeWindows("c:/", "c:\\aaaa\\bbbb", "aaaa\\bbbb"); + try testRelativeWindows("c:/aaaa/bbbb", "d:\\", "D:\\"); + try testRelativeWindows("c:/AaAa/bbbb", "c:/aaaa/bbbb", ""); + try testRelativeWindows("c:/aaaaa/", "c:/aaaa/cccc", "..\\aaaa\\cccc"); + try testRelativeWindows("C:\\foo\\bar\\baz\\quux", "C:\\", "..\\..\\..\\.."); + try testRelativeWindows("C:\\foo\\test", "C:\\foo\\test\\bar\\package.json", "bar\\package.json"); + try testRelativeWindows("C:\\foo\\bar\\baz-quux", "C:\\foo\\bar\\baz", "..\\baz"); + try testRelativeWindows("C:\\foo\\bar\\baz", "C:\\foo\\bar\\baz-quux", "..\\baz-quux"); + try testRelativeWindows("\\\\foo\\bar", "\\\\foo\\bar\\baz", "baz"); + try testRelativeWindows("\\\\foo\\bar\\baz", "\\\\foo\\bar", ".."); + try testRelativeWindows("\\\\foo\\bar\\baz-quux", "\\\\foo\\bar\\baz", "..\\baz"); + try testRelativeWindows("\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz-quux", "..\\baz-quux"); + try testRelativeWindows("C:\\baz-quux", "C:\\baz", "..\\baz"); + try testRelativeWindows("C:\\baz", "C:\\baz-quux", "..\\baz-quux"); + try testRelativeWindows("\\\\foo\\baz-quux", "\\\\foo\\baz", "..\\baz"); + try testRelativeWindows("\\\\foo\\baz", "\\\\foo\\baz-quux", "..\\baz-quux"); + try testRelativeWindows("C:\\baz", "\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz"); + try testRelativeWindows("\\\\foo\\bar\\baz", "C:\\baz", "C:\\baz"); + + try testRelativePosix("/var/lib", "/var", ".."); + try testRelativePosix("/var/lib", "/bin", "../../bin"); + try testRelativePosix("/var/lib", "/var/lib", ""); + try testRelativePosix("/var/lib", "/var/apache", "../apache"); + try testRelativePosix("/var/", "/var/lib", "lib"); + try testRelativePosix("/", "/var/lib", "var/lib"); + try testRelativePosix("/foo/test", "/foo/test/bar/package.json", "bar/package.json"); + try testRelativePosix("/Users/a/web/b/test/mails", "/Users/a/web/b", "../.."); + try testRelativePosix("/foo/bar/baz-quux", "/foo/bar/baz", "../baz"); + try testRelativePosix("/foo/bar/baz", "/foo/bar/baz-quux", "../baz-quux"); + try testRelativePosix("/baz-quux", "/baz", "../baz"); + try testRelativePosix("/baz", "/baz-quux", "../baz-quux"); } -fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) void { - const result = relativePosix(testing.allocator, from, to) catch unreachable; +fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) !void { + const result = try relativePosix(testing.leak_count_allocator, from, to); + defer testing.leak_count_allocator.free(result); testing.expectEqualSlices(u8, expected_output, result); } -fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) void { - const result = relativeWindows(testing.allocator, from, to) catch unreachable; +fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) !void { + const result = try relativeWindows(testing.leak_count_allocator, from, to); + defer testing.leak_count_allocator.free(result); testing.expectEqualSlices(u8, expected_output, result); } diff --git a/lib/std/linked_list.zig b/lib/std/linked_list.zig index a21c9a83eb..d1652a8047 100644 --- a/lib/std/linked_list.zig +++ b/lib/std/linked_list.zig @@ -143,7 +143,7 @@ pub fn SinglyLinkedList(comptime T: type) type { } test "basic SinglyLinkedList test" { - const allocator = testing.allocator; + const allocator = testing.leak_count_allocator; var list = SinglyLinkedList(u32).init(); var one = try list.createNode(1, allocator); @@ -404,7 +404,7 @@ pub fn TailQueue(comptime T: type) type { } test "basic TailQueue test" { - const allocator = testing.allocator; + const allocator = testing.leak_count_allocator; var list = TailQueue(u32).init(); var one = try list.createNode(1, allocator); @@ -456,7 +456,7 @@ test "basic TailQueue test" { } test "TailQueue concatenation" { - const allocator = testing.allocator; + const allocator = testing.leak_count_allocator; var list1 = TailQueue(u32).init(); var list2 = TailQueue(u32).init(); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 0d3be9e7e4..2e60fe500e 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -9,7 +9,7 @@ const elf = std.elf; const File = std.fs.File; const Thread = std.Thread; -const a = std.testing.allocator; +const a = std.testing.leak_count_allocator; const builtin = @import("builtin"); const AtomicRmwOp = builtin.AtomicRmwOp; diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig index e726a07a88..9c07d20798 100644 --- a/lib/std/priority_queue.zig +++ b/lib/std/priority_queue.zig @@ -239,7 +239,7 @@ fn greaterThan(a: u32, b: u32) bool { const PQ = PriorityQueue(u32); test "std.PriorityQueue: add and remove min heap" { - var queue = PQ.init(testing.allocator, lessThan); + var queue = PQ.init(testing.leak_count_allocator, lessThan); defer queue.deinit(); try queue.add(54); @@ -257,7 +257,7 @@ test "std.PriorityQueue: add and remove min heap" { } test "std.PriorityQueue: add and remove same min heap" { - var queue = PQ.init(testing.allocator, lessThan); + var queue = PQ.init(testing.leak_count_allocator, lessThan); defer queue.deinit(); try queue.add(1); @@ -275,14 +275,14 @@ test "std.PriorityQueue: add and remove same min heap" { } test "std.PriorityQueue: removeOrNull on empty" { - var queue = PQ.init(testing.allocator, lessThan); + var queue = PQ.init(testing.leak_count_allocator, lessThan); defer queue.deinit(); expect(queue.removeOrNull() == null); } test "std.PriorityQueue: edge case 3 elements" { - var queue = PQ.init(testing.allocator, lessThan); + var queue = PQ.init(testing.leak_count_allocator, lessThan); defer queue.deinit(); try queue.add(9); @@ -294,7 +294,7 @@ test "std.PriorityQueue: edge case 3 elements" { } test "std.PriorityQueue: peek" { - var queue = PQ.init(testing.allocator, lessThan); + var queue = PQ.init(testing.leak_count_allocator, lessThan); defer queue.deinit(); expect(queue.peek() == null); @@ -306,7 +306,7 @@ test "std.PriorityQueue: peek" { } test "std.PriorityQueue: sift up with odd indices" { - var queue = PQ.init(testing.allocator, lessThan); + var queue = PQ.init(testing.leak_count_allocator, lessThan); defer queue.deinit(); const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; for (items) |e| { @@ -320,7 +320,7 @@ test "std.PriorityQueue: sift up with odd indices" { } test "std.PriorityQueue: addSlice" { - var queue = PQ.init(testing.allocator, lessThan); + var queue = PQ.init(testing.leak_count_allocator, lessThan); defer queue.deinit(); const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; try queue.addSlice(items[0..]); @@ -333,8 +333,8 @@ test "std.PriorityQueue: addSlice" { test "std.PriorityQueue: fromOwnedSlice" { const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; - const heap_items = try std.mem.dupe(testing.allocator, u32, items[0..]); - var queue = PQ.fromOwnedSlice(testing.allocator, lessThan, heap_items[0..]); + const heap_items = try std.mem.dupe(testing.leak_count_allocator, u32, items[0..]); + var queue = PQ.fromOwnedSlice(testing.leak_count_allocator, lessThan, heap_items[0..]); defer queue.deinit(); const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 }; @@ -344,7 +344,7 @@ test "std.PriorityQueue: fromOwnedSlice" { } test "std.PriorityQueue: add and remove max heap" { - var queue = PQ.init(testing.allocator, greaterThan); + var queue = PQ.init(testing.leak_count_allocator, greaterThan); defer queue.deinit(); try queue.add(54); @@ -362,7 +362,7 @@ test "std.PriorityQueue: add and remove max heap" { } test "std.PriorityQueue: add and remove same max heap" { - var queue = PQ.init(testing.allocator, greaterThan); + var queue = PQ.init(testing.leak_count_allocator, greaterThan); defer queue.deinit(); try queue.add(1); @@ -380,8 +380,8 @@ test "std.PriorityQueue: add and remove same max heap" { } test "std.PriorityQueue: iterator" { - var queue = PQ.init(testing.allocator, lessThan); - var map = std.AutoHashMap(u32, void).init(testing.allocator); + var queue = PQ.init(testing.leak_count_allocator, lessThan); + var map = std.AutoHashMap(u32, void).init(testing.leak_count_allocator); defer { queue.deinit(); map.deinit(); @@ -402,7 +402,7 @@ test "std.PriorityQueue: iterator" { } test "std.PriorityQueue: remove at index" { - var queue = PQ.init(testing.allocator, lessThan); + var queue = PQ.init(testing.leak_count_allocator, lessThan); defer queue.deinit(); try queue.add(3); diff --git a/lib/std/process.zig b/lib/std/process.zig index 2758e25ac0..19f0eac235 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -114,7 +114,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { } test "os.getEnvMap" { - var env = try getEnvMap(std.testing.allocator); + var env = try getEnvMap(std.testing.leak_count_allocator); defer env.deinit(); } @@ -165,7 +165,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } test "os.getEnvVarOwned" { - var ga = std.testing.allocator; + var ga = std.testing.leak_count_allocator; testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV")); } @@ -492,10 +492,11 @@ test "windows arg parsing" { fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void { var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line); for (expected_args) |expected_arg| { - const arg = it.next(std.testing.allocator).? catch unreachable; + const arg = it.next(std.testing.leak_count_allocator).? catch unreachable; + defer std.testing.leak_count_allocator.free(arg); testing.expectEqualSlices(u8, expected_arg, arg); } - testing.expect(it.next(std.testing.allocator) == null); + testing.expect(it.next(std.testing.leak_count_allocator) == null); } pub const UserInfo = struct { diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index 286dfbed1b..e519f7f766 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -14,6 +14,7 @@ pub fn main() anyerror!void { for (test_fn_list) |test_fn, i| { std.testing.allocator_instance.reset(); + var test_node = root_node.start(test_fn.name, null); test_node.activate(); progress.refresh(); @@ -36,6 +37,8 @@ pub fn main() anyerror!void { return err; }, } + + try std.testing.leak_count_allocator_instance.validate(); } root_node.end(); if (ok_count == test_fn_list.len) { diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 02d7cdb393..58298708c3 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -7,6 +7,48 @@ pub const allocator = &allocator_instance.allocator; pub var allocator_instance = std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..]); var allocator_mem: [100 * 1024]u8 = undefined; +pub const leak_count_allocator = &leak_count_allocator_instance.allocator; +pub var leak_count_allocator_instance = LeakCountAllocator.init(allocator); +const LeakCountAllocator = struct { + count: usize, + allocator: std.mem.Allocator, + internal_allocator: *std.mem.Allocator, + + fn init(allo: *std.mem.Allocator) LeakCountAllocator { + return .{ + .count = 0, + .allocator = .{ + .reallocFn = realloc, + .shrinkFn = shrink, + }, + .internal_allocator = allo, + }; + } + + fn realloc(allo: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { + const self = @fieldParentPtr(LeakCountAllocator, "allocator", allo); + if (old_mem.len == 0) { + self.count += 1; + } + return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + } + + fn shrink(allo: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { + const self = @fieldParentPtr(LeakCountAllocator, "allocator", allo); + if (new_size == 0) { + self.count -= 1; + } + return self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + } + + fn validate(self: LeakCountAllocator) !void { + if (self.count > 0) { + std.debug.warn("Detected leaked allocations without matching free: {}\n", .{self.count}); + return error.Leak; + } + } +}; + /// This function is intended to be used only in tests. It prints diagnostics to stderr /// and then aborts when actual_error_union is not expected_error. pub fn expectError(expected_error: anyerror, actual_error_union: var) void { diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 638b5f5e2f..1884796835 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -501,14 +501,16 @@ test "utf16leToUtf8" { { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); - const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); + defer std.testing.leak_count_allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "Aa")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); - const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); + defer std.testing.leak_count_allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } @@ -516,7 +518,8 @@ test "utf16leToUtf8" { // the values just outside the surrogate half range mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); - const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); + defer std.testing.leak_count_allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } @@ -524,7 +527,8 @@ test "utf16leToUtf8" { // smallest surrogate pair mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); - const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); + defer std.testing.leak_count_allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } @@ -532,14 +536,16 @@ test "utf16leToUtf8" { // largest surrogate pair mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); - const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); + defer std.testing.leak_count_allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); - const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); + defer std.testing.leak_count_allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } } diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index e339343823..c967c78789 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -2287,7 +2287,7 @@ pub const Node = struct { test "iterate" { var root = Node.Root{ .base = Node{ .id = Node.Id.Root }, - .decls = Node.Root.DeclList.init(std.testing.allocator), + .decls = Node.Root.DeclList.init(std.testing.leak_count_allocator), .eof_token = 0, }; var base = &root.base; diff --git a/test/compare_output.zig b/test/compare_output.zig index 7a41d46f54..d743e0784a 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -445,7 +445,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\const std = @import("std"); \\const io = std.io; \\const os = std.os; - \\const allocator = std.testing.allocator; + \\const allocator = std.testing.leak_count_allocator; \\ \\pub fn main() !void { \\ var args_it = std.process.args(); @@ -486,7 +486,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\const std = @import("std"); \\const io = std.io; \\const os = std.os; - \\const allocator = std.testing.allocator; + \\const allocator = std.testing.leak_count_allocator; \\ \\pub fn main() !void { \\ var args_it = std.process.args(); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 341062e161..2f3f0a9f1f 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5765,7 +5765,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() void { \\ const a = MdNode.Header { - \\ .text = MdText.init(&std.testing.allocator), + \\ .text = MdText.init(&std.testing.leak_count_allocator), \\ .weight = HeaderWeight.H1, \\ }; \\} diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig index cf650ae88e..848a4780e5 100644 --- a/test/stage1/behavior/const_slice_child.zig +++ b/test/stage1/behavior/const_slice_child.zig @@ -22,7 +22,7 @@ fn foo(args: [][]const u8) void { } fn bar(argc: usize) void { - const args = testing.allocator.alloc([]const u8, argc) catch unreachable; + const args = testing.leak_count_allocator.alloc([]const u8, argc) catch unreachable; for (args) |_, i| { const ptr = argv[i]; args[i] = ptr[0..strlen(ptr)]; diff --git a/test/standalone/brace_expansion/main.zig b/test/standalone/brace_expansion/main.zig index c6bfd02e79..33fe826d18 100644 --- a/test/standalone/brace_expansion/main.zig +++ b/test/standalone/brace_expansion/main.zig @@ -201,7 +201,7 @@ pub fn main() !void { } test "invalid inputs" { - global_allocator = std.testing.allocator; + global_allocator = std.testing.leak_count_allocator; expectError("}ABC", error.InvalidInput); expectError("{ABC", error.InvalidInput); @@ -222,7 +222,7 @@ fn expectError(test_input: []const u8, expected_err: anyerror) void { } test "valid inputs" { - global_allocator = std.testing.allocator; + global_allocator = std.testing.leak_count_allocator; expectExpansion("{x,y,z}", "x y z"); expectExpansion("{A,B}{x,y}", "Ax Ay Bx By"); diff --git a/test/standalone/cat/main.zig b/test/standalone/cat/main.zig index 34439f9c24..10ec00d6e8 100644 --- a/test/standalone/cat/main.zig +++ b/test/standalone/cat/main.zig @@ -4,7 +4,7 @@ const process = std.process; const fs = std.fs; const mem = std.mem; const warn = std.debug.warn; -const allocator = std.testing.allocator; +const allocator = std.testing.leak_count_allocator; pub fn main() !void { var args_it = process.args(); diff --git a/test/standalone/empty_env/main.zig b/test/standalone/empty_env/main.zig index f4ebf56136..dc2ac73738 100644 --- a/test/standalone/empty_env/main.zig +++ b/test/standalone/empty_env/main.zig @@ -1,6 +1,6 @@ const std = @import("std"); pub fn main() void { - const env_map = std.process.getEnvMap(std.testing.allocator) catch @panic("unable to get env map"); + const env_map = std.process.getEnvMap(std.testing.leak_count_allocator) catch @panic("unable to get env map"); std.testing.expect(env_map.count() == 0); } diff --git a/test/standalone/load_dynamic_library/main.zig b/test/standalone/load_dynamic_library/main.zig index 70fc4986ac..5a2e55e937 100644 --- a/test/standalone/load_dynamic_library/main.zig +++ b/test/standalone/load_dynamic_library/main.zig @@ -1,8 +1,8 @@ const std = @import("std"); pub fn main() !void { - const args = try std.process.argsAlloc(std.testing.allocator); - defer std.process.argsFree(std.testing.allocator, args); + const args = try std.process.argsAlloc(std.testing.leak_count_allocator); + defer std.process.argsFree(std.testing.leak_count_allocator, args); const dynlib_name = args[1]; -- cgit v1.2.3 From 4a4d6f2be911cae08db434f877a1be2340d262c8 Mon Sep 17 00:00:00 2001 From: Rocknest <35231115+Rocknest@users.noreply.github.com> Date: Wed, 29 Jan 2020 23:15:17 +0200 Subject: Reorganize definitions --- lib/std/debug.zig | 251 +------------------------------------------- lib/std/os/windows/bits.zig | 229 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 230 insertions(+), 250 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index acc3f36412..9c1d211805 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -2317,11 +2317,11 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.Stdcall) c } } -// zig won't let me use an anon enum here +// zig won't let me use an anon enum here https://github.com/ziglang/zig/issues/3707 fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u8, comptime format: ?[]const u8) noreturn { const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress); - if (comptime windows_exception_context.haveContext) { - const regs = windows_exception_context.getRegs(info.ContextRecord); + if (@hasDecl(windows, "CONTEXT")) { + const regs = info.ContextRecord.getRegs(); switch (msg) { 0 => std.debug.warn("{}\n", .{format.?}), 1 => std.debug.warn("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), @@ -2341,251 +2341,6 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u } } -pub const windows_exception_context = switch (builtin.arch) { - .i386 => struct { - pub const haveContext = true; - - pub fn getRegs(ptr: *c_void) struct {bp: usize, ip: usize} { - const ctx = @ptrCast(*const CONTEXT, @alignCast(@alignOf(CONTEXT), ptr)); - return .{.bp = @intCast(usize, ctx.Ebp), .ip = @intCast(usize, ctx.Eip)}; - } - - pub const CONTEXT = extern struct { - ContextFlags: DWORD, - Dr0: DWORD, - Dr1: DWORD, - Dr2: DWORD, - Dr3: DWORD, - Dr6: DWORD, - Dr7: DWORD, - FloatSave: FLOATING_SAVE_AREA, - SegGs: DWORD, - SegFs: DWORD, - SegEs: DWORD, - SegDs: DWORD, - Edi: DWORD, - Esi: DWORD, - Ebx: DWORD, - Edx: DWORD, - Ecx: DWORD, - Eax: DWORD, - Ebp: DWORD, - Eip: DWORD, - SegCs: DWORD, - EFlags: DWORD, - Esp: DWORD, - SegSs: DWORD, - ExtendedRegisters: [512]BYTE, - }; - - pub const FLOATING_SAVE_AREA = extern struct { - ControlWord: DWORD, - StatusWord: DWORD, - TagWord: DWORD, - ErrorOffset: DWORD, - ErrorSelector: DWORD, - DataOffset: DWORD, - DataSelector: DWORD, - RegisterArea: [80]BYTE, - Cr0NpxState: DWORD, - }; - - pub const BYTE = u8; - pub const DWORD = c_ulong; - }, - .x86_64 => struct { - pub const haveContext = true; - - pub fn getRegs(ptr: *c_void) struct {bp: usize, ip: usize} { - const ctx = @ptrCast(*const CONTEXT, @alignCast(@alignOf(CONTEXT), ptr)); - return .{.bp = @intCast(usize, ctx.Rbp), .ip = @intCast(usize, ctx.Rip)}; - } - - pub const CONTEXT = extern struct { - P1Home: DWORD64, - P2Home: DWORD64, - P3Home: DWORD64, - P4Home: DWORD64, - P5Home: DWORD64, - P6Home: DWORD64, - ContextFlags: DWORD, - MxCsr: DWORD, - SegCs: WORD, - SegDs: WORD, - SegEs: WORD, - SegFs: WORD, - SegGs: WORD, - SegSs: WORD, - EFlags: DWORD, - Dr0: DWORD64, - Dr1: DWORD64, - Dr2: DWORD64, - Dr3: DWORD64, - Dr6: DWORD64, - Dr7: DWORD64, - Rax: DWORD64, - Rcx: DWORD64, - Rdx: DWORD64, - Rbx: DWORD64, - Rsp: DWORD64, - Rbp: DWORD64, - Rsi: DWORD64, - Rdi: DWORD64, - R8: DWORD64, - R9: DWORD64, - R10: DWORD64, - R11: DWORD64, - R12: DWORD64, - R13: DWORD64, - R14: DWORD64, - R15: DWORD64, - Rip: DWORD64, - DUMMYUNIONNAME: extern union { - FltSave: XMM_SAVE_AREA32, - FloatSave: XMM_SAVE_AREA32, - DUMMYSTRUCTNAME: extern struct { - Header: [2]M128A, - Legacy: [8]M128A, - Xmm0: M128A, - Xmm1: M128A, - Xmm2: M128A, - Xmm3: M128A, - Xmm4: M128A, - Xmm5: M128A, - Xmm6: M128A, - Xmm7: M128A, - Xmm8: M128A, - Xmm9: M128A, - Xmm10: M128A, - Xmm11: M128A, - Xmm12: M128A, - Xmm13: M128A, - Xmm14: M128A, - Xmm15: M128A, - }, - }, - VectorRegister: [26]M128A, - VectorControl: DWORD64, - DebugControl: DWORD64, - LastBranchToRip: DWORD64, - LastBranchFromRip: DWORD64, - LastExceptionToRip: DWORD64, - LastExceptionFromRip: DWORD64, - }; - - pub const XMM_SAVE_AREA32 = extern struct { - ControlWord: WORD, - StatusWord: WORD, - TagWord: BYTE, - Reserved1: BYTE, - ErrorOpcode: WORD, - ErrorOffset: DWORD, - ErrorSelector: WORD, - Reserved2: WORD, - DataOffset: DWORD, - DataSelector: WORD, - Reserved3: WORD, - MxCsr: DWORD, - MxCsr_Mask: DWORD, - FloatRegisters: [8]M128A, - XmmRegisters: [16]M128A, - Reserved4: [96]BYTE, - }; - - pub const M128A = extern struct { - Low: ULONGLONG, - High: LONGLONG, - }; - - pub const BYTE = u8; - pub const WORD = u16; - pub const DWORD = u32; - pub const DWORD64 = u64; - pub const LONGLONG = c_longlong; - pub const ULONGLONG = c_ulonglong; - }, - .aarch64 => struct { - pub const haveContext = true; - - pub fn getRegs(ptr: *c_void) struct {bp: usize, ip: usize} { - const ctx = @ptrCast(*const CONTEXT, @alignCast(@alignOf(CONTEXT), ptr)); - return .{.bp = @intCast(usize, ctx.Fp), .ip = @intCast(usize, ctx.Pc)}; - } - - pub const CONTEXT = extern struct { - ContextFlags: ULONG, - Cpsr: ULONG, - DUMMYUNIONNAME: extern union { - DUMMYSTRUCTNAME: extern struct { - X0: DWORD64, - X1: DWORD64, - X2: DWORD64, - X3: DWORD64, - X4: DWORD64, - X5: DWORD64, - X6: DWORD64, - X7: DWORD64, - X8: DWORD64, - X9: DWORD64, - X10: DWORD64, - X11: DWORD64, - X12: DWORD64, - X13: DWORD64, - X14: DWORD64, - X15: DWORD64, - X16: DWORD64, - X17: DWORD64, - X18: DWORD64, - X19: DWORD64, - X20: DWORD64, - X21: DWORD64, - X22: DWORD64, - X23: DWORD64, - X24: DWORD64, - X25: DWORD64, - X26: DWORD64, - X27: DWORD64, - X28: DWORD64, - Fp: DWORD64, - Lr: DWORD64, - }, - X: [31]DWORD64, - }, - Sp: DWORD64, - Pc: DWORD64, - V: [32]NEON128, - Fpcr: DWORD, - Fpsr: DWORD, - Bcr: [8]DWORD, - Bvr: [8]DWORD64, - Wcr: [2]DWORD, - Wvr: [2]DWORD64, - }; - - pub const NEON128 = extern union { - DUMMYSTRUCTNAME: extern struct { - Low: ULONGLONG, - High: LONGLONG, - }, - D: [2]f64, - S: [4]f32, - H: [8]WORD, - B: [16]BYTE, - }; - - pub const ULONG = c_ulong; - pub const LONGLONG = c_longlong; - pub const ULONGLONG = c_ulonglong; - pub const BYTE = u8; - pub const WORD = c_ushort; - pub const DWORD = c_ulong; - pub const DWORD64 = c_ulonglong; - }, - else => struct { - pub const haveContext = false; - }, -}; - pub fn dumpStackPointerAddr(prefix: []const u8) void { const sp = asm ("" : [argc] "={rsp}" (-> usize) diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig index 328732e0c7..e4c685494a 100644 --- a/lib/std/os/windows/bits.zig +++ b/lib/std/os/windows/bits.zig @@ -23,7 +23,6 @@ pub const BOOL = c_int; pub const BOOLEAN = BYTE; pub const BYTE = u8; pub const CHAR = u8; -pub const DWORD = u32; pub const FLOAT = f32; pub const HANDLE = *c_void; pub const HCRYPTPROV = ULONG_PTR; @@ -52,6 +51,8 @@ pub const DWORD_PTR = ULONG_PTR; pub const UNICODE = false; pub const WCHAR = u16; pub const WORD = u16; +pub const DWORD = u32; +pub const DWORD64 = u64; pub const LARGE_INTEGER = i64; pub const USHORT = u16; pub const SHORT = i16; @@ -887,9 +888,233 @@ pub const EXCEPTION_RECORD = extern struct { ExceptionInformation: [15]usize, }; +pub usingnamespace switch (builtin.arch) { + .i386 => struct { + pub const FLOATING_SAVE_AREA = extern struct { + ControlWord: DWORD, + StatusWord: DWORD, + TagWord: DWORD, + ErrorOffset: DWORD, + ErrorSelector: DWORD, + DataOffset: DWORD, + DataSelector: DWORD, + RegisterArea: [80]BYTE, + Cr0NpxState: DWORD, + }; + + pub const CONTEXT = extern struct { + ContextFlags: DWORD, + Dr0: DWORD, + Dr1: DWORD, + Dr2: DWORD, + Dr3: DWORD, + Dr6: DWORD, + Dr7: DWORD, + FloatSave: FLOATING_SAVE_AREA, + SegGs: DWORD, + SegFs: DWORD, + SegEs: DWORD, + SegDs: DWORD, + Edi: DWORD, + Esi: DWORD, + Ebx: DWORD, + Edx: DWORD, + Ecx: DWORD, + Eax: DWORD, + Ebp: DWORD, + Eip: DWORD, + SegCs: DWORD, + EFlags: DWORD, + Esp: DWORD, + SegSs: DWORD, + ExtendedRegisters: [512]BYTE, + + pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} { + return .{.bp = @intCast(usize, ctx.Ebp), .ip = @intCast(usize, ctx.Eip)}; + } + }; + + pub const PCONTEXT = *CONTEXT; + }, + .x86_64 => struct { + pub const M128A = extern struct { + Low: ULONGLONG, + High: LONGLONG, + }; + + pub const XMM_SAVE_AREA32 = extern struct { + ControlWord: WORD, + StatusWord: WORD, + TagWord: BYTE, + Reserved1: BYTE, + ErrorOpcode: WORD, + ErrorOffset: DWORD, + ErrorSelector: WORD, + Reserved2: WORD, + DataOffset: DWORD, + DataSelector: WORD, + Reserved3: WORD, + MxCsr: DWORD, + MxCsr_Mask: DWORD, + FloatRegisters: [8]M128A, + XmmRegisters: [16]M128A, + Reserved4: [96]BYTE, + }; + + pub const CONTEXT = extern struct { + P1Home: DWORD64, + P2Home: DWORD64, + P3Home: DWORD64, + P4Home: DWORD64, + P5Home: DWORD64, + P6Home: DWORD64, + ContextFlags: DWORD, + MxCsr: DWORD, + SegCs: WORD, + SegDs: WORD, + SegEs: WORD, + SegFs: WORD, + SegGs: WORD, + SegSs: WORD, + EFlags: DWORD, + Dr0: DWORD64, + Dr1: DWORD64, + Dr2: DWORD64, + Dr3: DWORD64, + Dr6: DWORD64, + Dr7: DWORD64, + Rax: DWORD64, + Rcx: DWORD64, + Rdx: DWORD64, + Rbx: DWORD64, + Rsp: DWORD64, + Rbp: DWORD64, + Rsi: DWORD64, + Rdi: DWORD64, + R8: DWORD64, + R9: DWORD64, + R10: DWORD64, + R11: DWORD64, + R12: DWORD64, + R13: DWORD64, + R14: DWORD64, + R15: DWORD64, + Rip: DWORD64, + DUMMYUNIONNAME: extern union { + FltSave: XMM_SAVE_AREA32, + FloatSave: XMM_SAVE_AREA32, + DUMMYSTRUCTNAME: extern struct { + Header: [2]M128A, + Legacy: [8]M128A, + Xmm0: M128A, + Xmm1: M128A, + Xmm2: M128A, + Xmm3: M128A, + Xmm4: M128A, + Xmm5: M128A, + Xmm6: M128A, + Xmm7: M128A, + Xmm8: M128A, + Xmm9: M128A, + Xmm10: M128A, + Xmm11: M128A, + Xmm12: M128A, + Xmm13: M128A, + Xmm14: M128A, + Xmm15: M128A, + }, + }, + VectorRegister: [26]M128A, + VectorControl: DWORD64, + DebugControl: DWORD64, + LastBranchToRip: DWORD64, + LastBranchFromRip: DWORD64, + LastExceptionToRip: DWORD64, + LastExceptionFromRip: DWORD64, + + pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} { + return .{.bp = @intCast(usize, ctx.Rbp), .ip = @intCast(usize, ctx.Rip)}; + } + }; + + pub const PCONTEXT = *CONTEXT; + }, + .aarch64 => struct { + pub const NEON128 = extern union { + DUMMYSTRUCTNAME: extern struct { + Low: ULONGLONG, + High: LONGLONG, + }, + D: [2]f64, + S: [4]f32, + H: [8]WORD, + B: [16]BYTE, + }; + + pub const CONTEXT = extern struct { + ContextFlags: ULONG, + Cpsr: ULONG, + DUMMYUNIONNAME: extern union { + DUMMYSTRUCTNAME: extern struct { + X0: DWORD64, + X1: DWORD64, + X2: DWORD64, + X3: DWORD64, + X4: DWORD64, + X5: DWORD64, + X6: DWORD64, + X7: DWORD64, + X8: DWORD64, + X9: DWORD64, + X10: DWORD64, + X11: DWORD64, + X12: DWORD64, + X13: DWORD64, + X14: DWORD64, + X15: DWORD64, + X16: DWORD64, + X17: DWORD64, + X18: DWORD64, + X19: DWORD64, + X20: DWORD64, + X21: DWORD64, + X22: DWORD64, + X23: DWORD64, + X24: DWORD64, + X25: DWORD64, + X26: DWORD64, + X27: DWORD64, + X28: DWORD64, + Fp: DWORD64, + Lr: DWORD64, + }, + X: [31]DWORD64, + }, + Sp: DWORD64, + Pc: DWORD64, + V: [32]NEON128, + Fpcr: DWORD, + Fpsr: DWORD, + Bcr: [8]DWORD, + Bvr: [8]DWORD64, + Wcr: [2]DWORD, + Wvr: [2]DWORD64, + + pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} { + return .{.bp = @intCast(usize, ctx.Fp), .ip = @intCast(usize, ctx.Pc)}; + } + }; + + pub const PCONTEXT = *CONTEXT; + }, + else => struct { + pub const PCONTEXT = *c_void; + }, +}; + pub const EXCEPTION_POINTERS = extern struct { ExceptionRecord: *EXCEPTION_RECORD, - ContextRecord: *c_void, + ContextRecord: PCONTEXT, }; pub const VECTORED_EXCEPTION_HANDLER = fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(.Stdcall) c_long; -- cgit v1.2.3 From c0c9c601d492e9da3f391ec4d837f7ab02b559df Mon Sep 17 00:00:00 2001 From: Rocknest <35231115+Rocknest@users.noreply.github.com> Date: Wed, 29 Jan 2020 23:48:52 +0200 Subject: Fix off-by-one error --- lib/std/debug.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 9c1d211805..2dd1da50c3 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -129,7 +129,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { return; }; const tty_config = detectTTYConfig(); - printSourceAtAddress(debug_info, stderr, if (builtin.os == .windows) (ip + 1) else ip, tty_config) catch return; + printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*; printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return; var it = StackIterator{ @@ -471,7 +471,7 @@ fn printSourceAtAddressWindows( line_index += @sizeOf(pdb.LineNumberEntry); const vaddr_start = frag_vaddr_start + line_num_entry.Offset; - if (relative_address <= vaddr_start) { + if (relative_address < vaddr_start) { break; } } -- cgit v1.2.3 From 0c137934cbd10528c2dced898b6c5485ab528e6d Mon Sep 17 00:00:00 2001 From: Benjamin Feng Date: Wed, 29 Jan 2020 17:26:10 -0600 Subject: Move FailingAllocator to testing --- lib/std/debug.zig | 10 +--- lib/std/debug/failing_allocator.zig | 81 -------------------------------- lib/std/io.zig | 2 +- lib/std/testing.zig | 45 ++---------------- lib/std/testing/failing_allocator.zig | 81 ++++++++++++++++++++++++++++++++ lib/std/testing/leak_count_allocator.zig | 46 ++++++++++++++++++ lib/std/zig/parser_test.zig | 4 +- 7 files changed, 137 insertions(+), 132 deletions(-) delete mode 100644 lib/std/debug/failing_allocator.zig create mode 100644 lib/std/testing/failing_allocator.zig create mode 100644 lib/std/testing/leak_count_allocator.zig (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7e1a99a395..32aba0d9b4 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -19,8 +19,8 @@ const windows = std.os.windows; pub const leb = @import("debug/leb128.zig"); -pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator; -pub const failing_allocator = &FailingAllocator.init(&global_fixed_allocator.allocator, 0).allocator; +pub const global_allocator = @compileError("Please switch to std.testing.leak_count_allocator."); +pub const failing_allocator = @compileError("Please switch to std.testing.failing_allocator."); pub const runtime_safety = switch (builtin.mode) { .Debug, .ReleaseSafe => true, @@ -2192,12 +2192,6 @@ fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) } } -pub const global_allocator = blk: { - @compileError("Please switch to std.testing.leak_count_allocator."); -}; -var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]); -var global_allocator_mem: [100 * 1024]u8 = undefined; - /// TODO multithreaded awareness var debug_info_allocator: ?*mem.Allocator = null; var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined; diff --git a/lib/std/debug/failing_allocator.zig b/lib/std/debug/failing_allocator.zig deleted file mode 100644 index 081a29cd97..0000000000 --- a/lib/std/debug/failing_allocator.zig +++ /dev/null @@ -1,81 +0,0 @@ -const std = @import("../std.zig"); -const mem = std.mem; - -/// Allocator that fails after N allocations, useful for making sure out of -/// memory conditions are handled correctly. -/// -/// To use this, first initialize it and get an allocator with -/// -/// `const failing_allocator = &FailingAllocator.init(, -/// ).allocator;` -/// -/// Then use `failing_allocator` anywhere you would have used a -/// different allocator. -pub const FailingAllocator = struct { - allocator: mem.Allocator, - index: usize, - fail_index: usize, - internal_allocator: *mem.Allocator, - allocated_bytes: usize, - freed_bytes: usize, - allocations: usize, - deallocations: usize, - - /// `fail_index` is the number of successful allocations you can - /// expect from this allocator. The next allocation will fail. - /// For example, if this is called with `fail_index` equal to 2, - /// the following test will pass: - /// - /// var a = try failing_alloc.create(i32); - /// var b = try failing_alloc.create(i32); - /// testing.expectError(error.OutOfMemory, failing_alloc.create(i32)); - pub fn init(allocator: *mem.Allocator, fail_index: usize) FailingAllocator { - return FailingAllocator{ - .internal_allocator = allocator, - .fail_index = fail_index, - .index = 0, - .allocated_bytes = 0, - .freed_bytes = 0, - .allocations = 0, - .deallocations = 0, - .allocator = mem.Allocator{ - .reallocFn = realloc, - .shrinkFn = shrink, - }, - }; - } - - fn realloc(allocator: *mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { - const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); - if (self.index == self.fail_index) { - return error.OutOfMemory; - } - const result = try self.internal_allocator.reallocFn( - self.internal_allocator, - old_mem, - old_align, - new_size, - new_align, - ); - if (new_size < old_mem.len) { - self.freed_bytes += old_mem.len - new_size; - if (new_size == 0) - self.deallocations += 1; - } else if (new_size > old_mem.len) { - self.allocated_bytes += new_size - old_mem.len; - if (old_mem.len == 0) - self.allocations += 1; - } - self.index += 1; - return result; - } - - fn shrink(allocator: *mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { - const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); - const r = self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); - self.freed_bytes += old_mem.len - r.len; - if (new_size == 0) - self.deallocations += 1; - return r; - } -}; diff --git a/lib/std/io.zig b/lib/std/io.zig index 93f2ae7680..a0e58c373d 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -891,7 +891,7 @@ pub fn readLineSlice(slice: []u8) ![]u8 { pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 { // We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte // after taking ownership, which would always require an allocation. - var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) }; + var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(testing.failing_allocator, slice) }; try buf.resize(0); return try readLineFrom(stream, &buf); } diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 58298708c3..07479a3852 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -7,47 +7,12 @@ pub const allocator = &allocator_instance.allocator; pub var allocator_instance = std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..]); var allocator_mem: [100 * 1024]u8 = undefined; -pub const leak_count_allocator = &leak_count_allocator_instance.allocator; -pub var leak_count_allocator_instance = LeakCountAllocator.init(allocator); -const LeakCountAllocator = struct { - count: usize, - allocator: std.mem.Allocator, - internal_allocator: *std.mem.Allocator, - - fn init(allo: *std.mem.Allocator) LeakCountAllocator { - return .{ - .count = 0, - .allocator = .{ - .reallocFn = realloc, - .shrinkFn = shrink, - }, - .internal_allocator = allo, - }; - } +pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator; +pub const failing_allocator = &FailingAllocator.init(allocator, 0).allocator; - fn realloc(allo: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { - const self = @fieldParentPtr(LeakCountAllocator, "allocator", allo); - if (old_mem.len == 0) { - self.count += 1; - } - return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, old_align, new_size, new_align); - } - - fn shrink(allo: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { - const self = @fieldParentPtr(LeakCountAllocator, "allocator", allo); - if (new_size == 0) { - self.count -= 1; - } - return self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); - } - - fn validate(self: LeakCountAllocator) !void { - if (self.count > 0) { - std.debug.warn("Detected leaked allocations without matching free: {}\n", .{self.count}); - return error.Leak; - } - } -}; +pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator; +pub var leak_count_allocator_instance = LeakCountAllocator.init(allocator); +pub const leak_count_allocator = &leak_count_allocator_instance.allocator; /// This function is intended to be used only in tests. It prints diagnostics to stderr /// and then aborts when actual_error_union is not expected_error. diff --git a/lib/std/testing/failing_allocator.zig b/lib/std/testing/failing_allocator.zig new file mode 100644 index 0000000000..081a29cd97 --- /dev/null +++ b/lib/std/testing/failing_allocator.zig @@ -0,0 +1,81 @@ +const std = @import("../std.zig"); +const mem = std.mem; + +/// Allocator that fails after N allocations, useful for making sure out of +/// memory conditions are handled correctly. +/// +/// To use this, first initialize it and get an allocator with +/// +/// `const failing_allocator = &FailingAllocator.init(, +/// ).allocator;` +/// +/// Then use `failing_allocator` anywhere you would have used a +/// different allocator. +pub const FailingAllocator = struct { + allocator: mem.Allocator, + index: usize, + fail_index: usize, + internal_allocator: *mem.Allocator, + allocated_bytes: usize, + freed_bytes: usize, + allocations: usize, + deallocations: usize, + + /// `fail_index` is the number of successful allocations you can + /// expect from this allocator. The next allocation will fail. + /// For example, if this is called with `fail_index` equal to 2, + /// the following test will pass: + /// + /// var a = try failing_alloc.create(i32); + /// var b = try failing_alloc.create(i32); + /// testing.expectError(error.OutOfMemory, failing_alloc.create(i32)); + pub fn init(allocator: *mem.Allocator, fail_index: usize) FailingAllocator { + return FailingAllocator{ + .internal_allocator = allocator, + .fail_index = fail_index, + .index = 0, + .allocated_bytes = 0, + .freed_bytes = 0, + .allocations = 0, + .deallocations = 0, + .allocator = mem.Allocator{ + .reallocFn = realloc, + .shrinkFn = shrink, + }, + }; + } + + fn realloc(allocator: *mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { + const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); + if (self.index == self.fail_index) { + return error.OutOfMemory; + } + const result = try self.internal_allocator.reallocFn( + self.internal_allocator, + old_mem, + old_align, + new_size, + new_align, + ); + if (new_size < old_mem.len) { + self.freed_bytes += old_mem.len - new_size; + if (new_size == 0) + self.deallocations += 1; + } else if (new_size > old_mem.len) { + self.allocated_bytes += new_size - old_mem.len; + if (old_mem.len == 0) + self.allocations += 1; + } + self.index += 1; + return result; + } + + fn shrink(allocator: *mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { + const self = @fieldParentPtr(FailingAllocator, "allocator", allocator); + const r = self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + self.freed_bytes += old_mem.len - r.len; + if (new_size == 0) + self.deallocations += 1; + return r; + } +}; diff --git a/lib/std/testing/leak_count_allocator.zig b/lib/std/testing/leak_count_allocator.zig new file mode 100644 index 0000000000..84c3248178 --- /dev/null +++ b/lib/std/testing/leak_count_allocator.zig @@ -0,0 +1,46 @@ +const std = @import("../std.zig"); + +/// This allocator is used in front of another allocator and counts the numbers of allocs and frees. +/// The test runner asserts every alloc has a corresponding free at the end of each test. +/// +/// The detection algorithm is incredibly primitive and only accounts for number of calls. +/// This should be replaced by the general purpose debug allocator. +pub const LeakCountAllocator = struct { + count: usize, + allocator: std.mem.Allocator, + internal_allocator: *std.mem.Allocator, + + pub fn init(allocator: *std.mem.Allocator) LeakCountAllocator { + return .{ + .count = 0, + .allocator = .{ + .reallocFn = realloc, + .shrinkFn = shrink, + }, + .internal_allocator = allocator, + }; + } + + fn realloc(allocator: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { + const self = @fieldParentPtr(LeakCountAllocator, "allocator", allocator); + if (old_mem.len == 0) { + self.count += 1; + } + return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + } + + fn shrink(allocator: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { + const self = @fieldParentPtr(LeakCountAllocator, "allocator", allocator); + if (new_size == 0) { + self.count -= 1; + } + return self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + } + + pub fn validate(self: LeakCountAllocator) !void { + if (self.count > 0) { + std.debug.warn("Detected leaked allocations without matching free: {}\n", .{self.count}); + return error.Leak; + } + } +}; diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index c57540ade9..1640d09992 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -2773,7 +2773,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { const needed_alloc_count = x: { // Try it once with unlimited memory, make sure it works var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); - var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, maxInt(usize)); + var failing_allocator = std.testing.FailingAllocator.init(&fixed_allocator.allocator, maxInt(usize)); var anything_changed: bool = undefined; const result_source = try testParse(source, &failing_allocator.allocator, &anything_changed); if (!mem.eql(u8, result_source, expected_source)) { @@ -2797,7 +2797,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { var fail_index: usize = 0; while (fail_index < needed_alloc_count) : (fail_index += 1) { var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); - var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); + var failing_allocator = std.testing.FailingAllocator.init(&fixed_allocator.allocator, fail_index); var anything_changed: bool = undefined; if (testParse(source, &failing_allocator.allocator, &anything_changed)) |_| { return error.NondeterministicMemoryUsage; -- cgit v1.2.3 From b077f3ab7d55374d2770336db236ecd7b18238a8 Mon Sep 17 00:00:00 2001 From: Benjamin Feng Date: Wed, 29 Jan 2020 21:22:01 -0600 Subject: Promoted "leak_count_allocator" to the main testing.allocator --- doc/docgen.zig | 4 ++-- lib/std/array_list.zig | 14 ++++++------ lib/std/buffer.zig | 6 ++--- lib/std/debug.zig | 2 +- lib/std/fifo.zig | 4 ++-- lib/std/fmt.zig | 10 ++++----- lib/std/fs/path.zig | 32 +++++++++++++-------------- lib/std/linked_list.zig | 6 ++--- lib/std/os/test.zig | 2 +- lib/std/priority_queue.zig | 28 +++++++++++------------ lib/std/process.zig | 10 ++++----- lib/std/special/test_runner.zig | 7 +++--- lib/std/testing.zig | 14 ++++++------ lib/std/testing/leak_count_allocator.zig | 2 +- lib/std/unicode.zig | 24 ++++++++++---------- lib/std/zig/ast.zig | 2 +- test/compare_output.zig | 4 ++-- test/compile_errors.zig | 2 +- test/stage1/behavior/const_slice_child.zig | 4 ++-- test/standalone/brace_expansion/main.zig | 4 ++-- test/standalone/cat/main.zig | 2 +- test/standalone/empty_env/main.zig | 2 +- test/standalone/load_dynamic_library/main.zig | 4 ++-- 23 files changed, 95 insertions(+), 94 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/doc/docgen.zig b/doc/docgen.zig index cc4993d65f..e94f3500e7 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -672,8 +672,8 @@ const TermState = enum { test "term color" { const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; - const result = try termColor(std.testing.leak_count_allocator, input_bytes); - defer std.testing.leak_count_allocator.free(result); + const result = try termColor(std.testing.allocator, input_bytes); + defer std.testing.allocator.free(result); testing.expectEqualSlices(u8, "AgreenB", result); } diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index 57c0d706a2..b028390465 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -320,7 +320,7 @@ test "std.ArrayList.basic" { } test "std.ArrayList.orderedRemove" { - var list = ArrayList(i32).init(testing.leak_count_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); try list.append(1); @@ -347,7 +347,7 @@ test "std.ArrayList.orderedRemove" { } test "std.ArrayList.swapRemove" { - var list = ArrayList(i32).init(testing.leak_count_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); try list.append(1); @@ -374,7 +374,7 @@ test "std.ArrayList.swapRemove" { } test "std.ArrayList.swapRemoveOrError" { - var list = ArrayList(i32).init(testing.leak_count_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); // Test just after initialization @@ -402,7 +402,7 @@ test "std.ArrayList.swapRemoveOrError" { } test "std.ArrayList.insert" { - var list = ArrayList(i32).init(testing.leak_count_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); try list.append(1); @@ -416,7 +416,7 @@ test "std.ArrayList.insert" { } test "std.ArrayList.insertSlice" { - var list = ArrayList(i32).init(testing.leak_count_allocator); + var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); try list.append(1); @@ -443,8 +443,8 @@ const Item = struct { }; test "std.ArrayList: ArrayList(T) of struct T" { - var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(testing.leak_count_allocator) }; + var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(testing.allocator) }; defer root.sub_items.deinit(); - try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(testing.leak_count_allocator) }); + try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(testing.allocator) }); testing.expect(root.sub_items.items[0].integer == 42); } diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig index cc1166e0e7..077b2b615f 100644 --- a/lib/std/buffer.zig +++ b/lib/std/buffer.zig @@ -150,7 +150,7 @@ pub const Buffer = struct { }; test "simple Buffer" { - var buf = try Buffer.init(testing.leak_count_allocator, ""); + var buf = try Buffer.init(testing.allocator, ""); defer buf.deinit(); testing.expect(buf.len() == 0); @@ -172,7 +172,7 @@ test "simple Buffer" { } test "Buffer.initSize" { - var buf = try Buffer.initSize(testing.leak_count_allocator, 3); + var buf = try Buffer.initSize(testing.allocator, 3); defer buf.deinit(); testing.expect(buf.len() == 3); try buf.append("hello"); @@ -180,7 +180,7 @@ test "Buffer.initSize" { } test "Buffer.initCapacity" { - var buf = try Buffer.initCapacity(testing.leak_count_allocator, 10); + var buf = try Buffer.initCapacity(testing.allocator, 10); defer buf.deinit(); testing.expect(buf.len() == 0); testing.expect(buf.capacity() >= 10); diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 32aba0d9b4..8468c4eaaf 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -19,7 +19,7 @@ const windows = std.os.windows; pub const leb = @import("debug/leb128.zig"); -pub const global_allocator = @compileError("Please switch to std.testing.leak_count_allocator."); +pub const global_allocator = @compileError("Please switch to std.testing.allocator."); pub const failing_allocator = @compileError("Please switch to std.testing.failing_allocator."); pub const runtime_safety = switch (builtin.mode) { diff --git a/lib/std/fifo.zig b/lib/std/fifo.zig index dd429289d1..ac8589f2ce 100644 --- a/lib/std/fifo.zig +++ b/lib/std/fifo.zig @@ -347,7 +347,7 @@ pub fn LinearFifo( } test "LinearFifo(u8, .Dynamic)" { - var fifo = LinearFifo(u8, .Dynamic).init(testing.leak_count_allocator); + var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); defer fifo.deinit(); try fifo.write("HELLO"); @@ -422,7 +422,7 @@ test "LinearFifo" { var fifo = switch (bt) { .Static => FifoType.init(), .Slice => FifoType.init(buf[0..]), - .Dynamic => FifoType.init(testing.leak_count_allocator), + .Dynamic => FifoType.init(testing.allocator), }; defer fifo.deinit(); diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 529131065c..627d8bc7ab 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1598,7 +1598,7 @@ test "hexToBytes" { test "formatIntValue with comptime_int" { const value: comptime_int = 123456789123456789; - var buf = try std.Buffer.init(std.testing.leak_count_allocator, ""); + var buf = try std.Buffer.init(std.testing.allocator, ""); defer buf.deinit(); try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append); std.testing.expect(mem.eql(u8, buf.toSlice(), "123456789123456789")); @@ -1653,22 +1653,22 @@ test "formatType max_depth" { inst.a = &inst; inst.tu.ptr = &inst.tu; - var buf0 = try std.Buffer.init(std.testing.leak_count_allocator, ""); + var buf0 = try std.Buffer.init(std.testing.allocator, ""); defer buf0.deinit(); try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0); std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }")); - var buf1 = try std.Buffer.init(std.testing.leak_count_allocator, ""); + var buf1 = try std.Buffer.init(std.testing.allocator, ""); defer buf1.deinit(); try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1); std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }")); - var buf2 = try std.Buffer.init(std.testing.leak_count_allocator, ""); + var buf2 = try std.Buffer.init(std.testing.allocator, ""); defer buf2.deinit(); try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2); std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }")); - var buf3 = try std.Buffer.init(std.testing.leak_count_allocator, ""); + var buf3 = try std.Buffer.init(std.testing.allocator, ""); defer buf3.deinit(); try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3); std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }")); diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 424e9f5759..66e24a4805 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -665,8 +665,8 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { } test "resolve" { - const cwd = try process.getCwdAlloc(testing.leak_count_allocator); - defer testing.leak_count_allocator.free(cwd); + const cwd = try process.getCwdAlloc(testing.allocator); + defer testing.allocator.free(cwd); if (builtin.os == .windows) { if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { cwd[0] = asciiUpper(cwd[0]); @@ -684,26 +684,26 @@ test "resolveWindows" { return error.SkipZigTest; } if (builtin.os == .windows) { - const cwd = try process.getCwdAlloc(testing.leak_count_allocator); - defer testing.leak_count_allocator.free(cwd); + const cwd = try process.getCwdAlloc(testing.allocator); + defer testing.allocator.free(cwd); const parsed_cwd = windowsParsePath(cwd); { - const expected = try join(testing.leak_count_allocator, &[_][]const u8{ + const expected = try join(testing.allocator, &[_][]const u8{ parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig", }); - defer testing.leak_count_allocator.free(expected); + defer testing.allocator.free(expected); if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } try testResolveWindows(&[_][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" }, expected); } { - const expected = try join(testing.leak_count_allocator, &[_][]const u8{ + const expected = try join(testing.allocator, &[_][]const u8{ cwd, "usr\\local\\lib\\zig", }); - defer testing.leak_count_allocator.free(expected); + defer testing.allocator.free(expected); if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } @@ -740,14 +740,14 @@ test "resolvePosix" { } fn testResolveWindows(paths: []const []const u8, expected: []const u8) !void { - const actual = try resolveWindows(testing.leak_count_allocator, paths); - defer testing.leak_count_allocator.free(actual); + const actual = try resolveWindows(testing.allocator, paths); + defer testing.allocator.free(actual); return testing.expect(mem.eql(u8, actual, expected)); } fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void { - const actual = try resolvePosix(testing.leak_count_allocator, paths); - defer testing.leak_count_allocator.free(actual); + const actual = try resolvePosix(testing.allocator, paths); + defer testing.allocator.free(actual); return testing.expect(mem.eql(u8, actual, expected)); } @@ -1172,13 +1172,13 @@ test "relative" { } fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) !void { - const result = try relativePosix(testing.leak_count_allocator, from, to); - defer testing.leak_count_allocator.free(result); + const result = try relativePosix(testing.allocator, from, to); + defer testing.allocator.free(result); testing.expectEqualSlices(u8, expected_output, result); } fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) !void { - const result = try relativeWindows(testing.leak_count_allocator, from, to); - defer testing.leak_count_allocator.free(result); + const result = try relativeWindows(testing.allocator, from, to); + defer testing.allocator.free(result); testing.expectEqualSlices(u8, expected_output, result); } diff --git a/lib/std/linked_list.zig b/lib/std/linked_list.zig index d1652a8047..a21c9a83eb 100644 --- a/lib/std/linked_list.zig +++ b/lib/std/linked_list.zig @@ -143,7 +143,7 @@ pub fn SinglyLinkedList(comptime T: type) type { } test "basic SinglyLinkedList test" { - const allocator = testing.leak_count_allocator; + const allocator = testing.allocator; var list = SinglyLinkedList(u32).init(); var one = try list.createNode(1, allocator); @@ -404,7 +404,7 @@ pub fn TailQueue(comptime T: type) type { } test "basic TailQueue test" { - const allocator = testing.leak_count_allocator; + const allocator = testing.allocator; var list = TailQueue(u32).init(); var one = try list.createNode(1, allocator); @@ -456,7 +456,7 @@ test "basic TailQueue test" { } test "TailQueue concatenation" { - const allocator = testing.leak_count_allocator; + const allocator = testing.allocator; var list1 = TailQueue(u32).init(); var list2 = TailQueue(u32).init(); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 2e60fe500e..0d3be9e7e4 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -9,7 +9,7 @@ const elf = std.elf; const File = std.fs.File; const Thread = std.Thread; -const a = std.testing.leak_count_allocator; +const a = std.testing.allocator; const builtin = @import("builtin"); const AtomicRmwOp = builtin.AtomicRmwOp; diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig index 9c07d20798..e726a07a88 100644 --- a/lib/std/priority_queue.zig +++ b/lib/std/priority_queue.zig @@ -239,7 +239,7 @@ fn greaterThan(a: u32, b: u32) bool { const PQ = PriorityQueue(u32); test "std.PriorityQueue: add and remove min heap" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); try queue.add(54); @@ -257,7 +257,7 @@ test "std.PriorityQueue: add and remove min heap" { } test "std.PriorityQueue: add and remove same min heap" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); try queue.add(1); @@ -275,14 +275,14 @@ test "std.PriorityQueue: add and remove same min heap" { } test "std.PriorityQueue: removeOrNull on empty" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); expect(queue.removeOrNull() == null); } test "std.PriorityQueue: edge case 3 elements" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); try queue.add(9); @@ -294,7 +294,7 @@ test "std.PriorityQueue: edge case 3 elements" { } test "std.PriorityQueue: peek" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); expect(queue.peek() == null); @@ -306,7 +306,7 @@ test "std.PriorityQueue: peek" { } test "std.PriorityQueue: sift up with odd indices" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; for (items) |e| { @@ -320,7 +320,7 @@ test "std.PriorityQueue: sift up with odd indices" { } test "std.PriorityQueue: addSlice" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; try queue.addSlice(items[0..]); @@ -333,8 +333,8 @@ test "std.PriorityQueue: addSlice" { test "std.PriorityQueue: fromOwnedSlice" { const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; - const heap_items = try std.mem.dupe(testing.leak_count_allocator, u32, items[0..]); - var queue = PQ.fromOwnedSlice(testing.leak_count_allocator, lessThan, heap_items[0..]); + const heap_items = try std.mem.dupe(testing.allocator, u32, items[0..]); + var queue = PQ.fromOwnedSlice(testing.allocator, lessThan, heap_items[0..]); defer queue.deinit(); const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 }; @@ -344,7 +344,7 @@ test "std.PriorityQueue: fromOwnedSlice" { } test "std.PriorityQueue: add and remove max heap" { - var queue = PQ.init(testing.leak_count_allocator, greaterThan); + var queue = PQ.init(testing.allocator, greaterThan); defer queue.deinit(); try queue.add(54); @@ -362,7 +362,7 @@ test "std.PriorityQueue: add and remove max heap" { } test "std.PriorityQueue: add and remove same max heap" { - var queue = PQ.init(testing.leak_count_allocator, greaterThan); + var queue = PQ.init(testing.allocator, greaterThan); defer queue.deinit(); try queue.add(1); @@ -380,8 +380,8 @@ test "std.PriorityQueue: add and remove same max heap" { } test "std.PriorityQueue: iterator" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); - var map = std.AutoHashMap(u32, void).init(testing.leak_count_allocator); + var queue = PQ.init(testing.allocator, lessThan); + var map = std.AutoHashMap(u32, void).init(testing.allocator); defer { queue.deinit(); map.deinit(); @@ -402,7 +402,7 @@ test "std.PriorityQueue: iterator" { } test "std.PriorityQueue: remove at index" { - var queue = PQ.init(testing.leak_count_allocator, lessThan); + var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); try queue.add(3); diff --git a/lib/std/process.zig b/lib/std/process.zig index 19f0eac235..dd5e124654 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -114,7 +114,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { } test "os.getEnvMap" { - var env = try getEnvMap(std.testing.leak_count_allocator); + var env = try getEnvMap(std.testing.allocator); defer env.deinit(); } @@ -165,7 +165,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } test "os.getEnvVarOwned" { - var ga = std.testing.leak_count_allocator; + var ga = std.testing.allocator; testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV")); } @@ -492,11 +492,11 @@ test "windows arg parsing" { fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void { var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line); for (expected_args) |expected_arg| { - const arg = it.next(std.testing.leak_count_allocator).? catch unreachable; - defer std.testing.leak_count_allocator.free(arg); + const arg = it.next(std.testing.allocator).? catch unreachable; + defer std.testing.allocator.free(arg); testing.expectEqualSlices(u8, expected_arg, arg); } - testing.expect(it.next(std.testing.leak_count_allocator) == null); + testing.expect(it.next(std.testing.allocator) == null); } pub const UserInfo = struct { diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index a5bbfff6fb..9a2d68a73d 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -13,10 +13,11 @@ pub fn main() anyerror!void { }; for (test_fn_list) |test_fn, i| { - std.testing.allocator_instance.reset(); + std.testing.base_allocator_instance.reset(); defer { - std.testing.leak_count_allocator_instance.validate() catch |err| { - @panic(@errorName(err)); + std.testing.allocator_instance.validate() catch |err| switch (err) { + error.Leak => std.debug.panic("", .{}), + else => std.debug.panic("error.{}", .{@errorName(err)}), }; } diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 07479a3852..4850f2e9b9 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -2,17 +2,17 @@ const builtin = @import("builtin"); const TypeId = builtin.TypeId; const std = @import("std.zig"); +pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator; +pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator; + /// This should only be used in temporary test programs. pub const allocator = &allocator_instance.allocator; -pub var allocator_instance = std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..]); -var allocator_mem: [100 * 1024]u8 = undefined; +pub var allocator_instance = LeakCountAllocator.init(&base_allocator_instance.allocator); -pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator; -pub const failing_allocator = &FailingAllocator.init(allocator, 0).allocator; +pub const failing_allocator = &FailingAllocator.init(&base_allocator_instance.allocator, 0).allocator; -pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator; -pub var leak_count_allocator_instance = LeakCountAllocator.init(allocator); -pub const leak_count_allocator = &leak_count_allocator_instance.allocator; +pub var base_allocator_instance = std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..]); +var allocator_mem: [100 * 1024]u8 = undefined; /// This function is intended to be used only in tests. It prints diagnostics to stderr /// and then aborts when actual_error_union is not expected_error. diff --git a/lib/std/testing/leak_count_allocator.zig b/lib/std/testing/leak_count_allocator.zig index 84c3248178..6cdcfa2678 100644 --- a/lib/std/testing/leak_count_allocator.zig +++ b/lib/std/testing/leak_count_allocator.zig @@ -39,7 +39,7 @@ pub const LeakCountAllocator = struct { pub fn validate(self: LeakCountAllocator) !void { if (self.count > 0) { - std.debug.warn("Detected leaked allocations without matching free: {}\n", .{self.count}); + std.debug.warn("error - detected leaked allocations without matching free: {}\n", .{self.count}); return error.Leak; } } diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 1884796835..77783c3edd 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -501,16 +501,16 @@ test "utf16leToUtf8" { { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); - const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); - defer std.testing.leak_count_allocator.free(utf8); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + defer std.testing.allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "Aa")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); - const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); - defer std.testing.leak_count_allocator.free(utf8); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + defer std.testing.allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } @@ -518,8 +518,8 @@ test "utf16leToUtf8" { // the values just outside the surrogate half range mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); - const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); - defer std.testing.leak_count_allocator.free(utf8); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + defer std.testing.allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } @@ -527,8 +527,8 @@ test "utf16leToUtf8" { // smallest surrogate pair mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); - const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); - defer std.testing.leak_count_allocator.free(utf8); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + defer std.testing.allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } @@ -536,16 +536,16 @@ test "utf16leToUtf8" { // largest surrogate pair mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); - const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); - defer std.testing.leak_count_allocator.free(utf8); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + defer std.testing.allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); - const utf8 = try utf16leToUtf8Alloc(std.testing.leak_count_allocator, &utf16le); - defer std.testing.leak_count_allocator.free(utf8); + const utf8 = try utf16leToUtf8Alloc(std.testing.allocator, &utf16le); + defer std.testing.allocator.free(utf8); testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } } diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index c967c78789..e339343823 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -2287,7 +2287,7 @@ pub const Node = struct { test "iterate" { var root = Node.Root{ .base = Node{ .id = Node.Id.Root }, - .decls = Node.Root.DeclList.init(std.testing.leak_count_allocator), + .decls = Node.Root.DeclList.init(std.testing.allocator), .eof_token = 0, }; var base = &root.base; diff --git a/test/compare_output.zig b/test/compare_output.zig index d743e0784a..7a41d46f54 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -445,7 +445,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\const std = @import("std"); \\const io = std.io; \\const os = std.os; - \\const allocator = std.testing.leak_count_allocator; + \\const allocator = std.testing.allocator; \\ \\pub fn main() !void { \\ var args_it = std.process.args(); @@ -486,7 +486,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\const std = @import("std"); \\const io = std.io; \\const os = std.os; - \\const allocator = std.testing.leak_count_allocator; + \\const allocator = std.testing.allocator; \\ \\pub fn main() !void { \\ var args_it = std.process.args(); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 2f3f0a9f1f..341062e161 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5765,7 +5765,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() void { \\ const a = MdNode.Header { - \\ .text = MdText.init(&std.testing.leak_count_allocator), + \\ .text = MdText.init(&std.testing.allocator), \\ .weight = HeaderWeight.H1, \\ }; \\} diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig index 7d969ae468..92e5121026 100644 --- a/test/stage1/behavior/const_slice_child.zig +++ b/test/stage1/behavior/const_slice_child.zig @@ -23,8 +23,8 @@ fn foo(args: [][]const u8) void { } fn bar(argc: usize) void { - const args = testing.leak_count_allocator.alloc([]const u8, argc) catch unreachable; - defer testing.leak_count_allocator.free(args); + const args = testing.allocator.alloc([]const u8, argc) catch unreachable; + defer testing.allocator.free(args); for (args) |_, i| { const ptr = argv[i]; args[i] = ptr[0..strlen(ptr)]; diff --git a/test/standalone/brace_expansion/main.zig b/test/standalone/brace_expansion/main.zig index 33fe826d18..c6bfd02e79 100644 --- a/test/standalone/brace_expansion/main.zig +++ b/test/standalone/brace_expansion/main.zig @@ -201,7 +201,7 @@ pub fn main() !void { } test "invalid inputs" { - global_allocator = std.testing.leak_count_allocator; + global_allocator = std.testing.allocator; expectError("}ABC", error.InvalidInput); expectError("{ABC", error.InvalidInput); @@ -222,7 +222,7 @@ fn expectError(test_input: []const u8, expected_err: anyerror) void { } test "valid inputs" { - global_allocator = std.testing.leak_count_allocator; + global_allocator = std.testing.allocator; expectExpansion("{x,y,z}", "x y z"); expectExpansion("{A,B}{x,y}", "Ax Ay Bx By"); diff --git a/test/standalone/cat/main.zig b/test/standalone/cat/main.zig index 10ec00d6e8..34439f9c24 100644 --- a/test/standalone/cat/main.zig +++ b/test/standalone/cat/main.zig @@ -4,7 +4,7 @@ const process = std.process; const fs = std.fs; const mem = std.mem; const warn = std.debug.warn; -const allocator = std.testing.leak_count_allocator; +const allocator = std.testing.allocator; pub fn main() !void { var args_it = process.args(); diff --git a/test/standalone/empty_env/main.zig b/test/standalone/empty_env/main.zig index dc2ac73738..f4ebf56136 100644 --- a/test/standalone/empty_env/main.zig +++ b/test/standalone/empty_env/main.zig @@ -1,6 +1,6 @@ const std = @import("std"); pub fn main() void { - const env_map = std.process.getEnvMap(std.testing.leak_count_allocator) catch @panic("unable to get env map"); + const env_map = std.process.getEnvMap(std.testing.allocator) catch @panic("unable to get env map"); std.testing.expect(env_map.count() == 0); } diff --git a/test/standalone/load_dynamic_library/main.zig b/test/standalone/load_dynamic_library/main.zig index 5a2e55e937..70fc4986ac 100644 --- a/test/standalone/load_dynamic_library/main.zig +++ b/test/standalone/load_dynamic_library/main.zig @@ -1,8 +1,8 @@ const std = @import("std"); pub fn main() !void { - const args = try std.process.argsAlloc(std.testing.leak_count_allocator); - defer std.process.argsFree(std.testing.leak_count_allocator, args); + const args = try std.process.argsAlloc(std.testing.allocator); + defer std.process.argsFree(std.testing.allocator, args); const dynlib_name = args[1]; -- cgit v1.2.3 From a5f18c2b2ae86126e0fd0cba67676ae68ba0f1df Mon Sep 17 00:00:00 2001 From: Rocknest <35231115+Rocknest@users.noreply.github.com> Date: Thu, 30 Jan 2020 10:00:28 +0200 Subject: Fix one more edge case --- lib/std/debug.zig | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 2dd1da50c3..9cd76cb30c 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -131,6 +131,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { const tty_config = detectTTYConfig(); printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*; + if (first_return_address == 0) return; // The whole call stack may be optimized out printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return; var it = StackIterator{ .first_addr = null, -- cgit v1.2.3 From e77a102e24c351a56cdda5bad5a46dcd58101c23 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 29 Jan 2020 18:40:52 +0100 Subject: Small DWARF fixups * Clang doesn't seem to emit a DW_AT_low_pc together with DW_AT_ranges for asm files. * Keep reading the other CUs if the lookup fails. --- lib/std/debug.zig | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index d035707a54..a5fd1a4712 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1390,8 +1390,12 @@ pub const DwarfInfo = struct { // All the addresses in the list are relative to the value // specified by DW_AT_low_pc or to some other value encoded - // in the list itself - var base_address = try compile_unit.die.getAttrAddr(DW.AT_low_pc); + // in the list itself. + // If no starting value is specified use zero. + var base_address = compile_unit.die.getAttrAddr(DW.AT_low_pc) catch |err| switch (err) { + error.MissingDebugInfo => 0, + else => return err, + }; try s.seekable_stream.seekTo(ranges_offset); @@ -1410,8 +1414,6 @@ pub const DwarfInfo = struct { return compile_unit; } } - - return error.InvalidDebugInfo; } else |err| { if (err != error.MissingDebugInfo) return err; continue; -- cgit v1.2.3 From 9b11e5e1f1e0debd1e5484883b2daad8b2b33cb7 Mon Sep 17 00:00:00 2001 From: Michaƫl Larouche Date: Tue, 21 Jan 2020 17:32:00 -0500 Subject: Add InstallRawStep to Zig build system that does a similar job to llvm-objcopy. To use it, do 'exe.installRaw("kernel.bin");' where exe is a LibExeObjStep Part of #2826 --- lib/std/build.zig | 13 +++ lib/std/build/emit_raw.zig | 255 ++++++++++++++++++++++++++++++++++++++++++++ lib/std/debug.zig | 14 +-- lib/std/elf.zig | 155 +++++++++++++++++---------- lib/std/target.zig | 17 +++ src-self-hosted/codegen.zig | 2 +- src-self-hosted/link.zig | 4 +- src-self-hosted/util.zig | 17 --- 8 files changed, 391 insertions(+), 86 deletions(-) create mode 100644 lib/std/build/emit_raw.zig (limited to 'lib/std/debug.zig') diff --git a/lib/std/build.zig b/lib/std/build.zig index 66660fc74c..54e5ea1c47 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -21,6 +21,7 @@ pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep; pub const WriteFileStep = @import("build/write_file.zig").WriteFileStep; pub const RunStep = @import("build/run.zig").RunStep; pub const CheckFileStep = @import("build/check_file.zig").CheckFileStep; +pub const InstallRawStep = @import("build/emit_raw.zig").InstallRawStep; pub const Builder = struct { install_tls: TopLevelStep, @@ -824,6 +825,10 @@ pub const Builder = struct { self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Lib, dest_rel_path).step); } + pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) void { + self.getInstallStep().dependOn(&self.addInstallRaw(artifact, dest_filename).step); + } + ///`dest_rel_path` is relative to install prefix path pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { return self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path); @@ -839,6 +844,10 @@ pub const Builder = struct { return self.addInstallFileWithDir(src_path, .Lib, dest_rel_path); } + pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep { + return InstallRawStep.create(self, artifact, dest_filename); + } + pub fn addInstallFileWithDir( self: *Builder, src_path: []const u8, @@ -1407,6 +1416,10 @@ pub const LibExeObjStep = struct { self.builder.installArtifact(self); } + pub fn installRaw(self: *LibExeObjStep, dest_filename: [] const u8) void { + self.builder.installRaw(self, dest_filename); + } + /// Creates a `RunStep` with an executable built with `addExecutable`. /// Add command line arguments with `addArg`. pub fn run(exe: *LibExeObjStep) *RunStep { diff --git a/lib/std/build/emit_raw.zig b/lib/std/build/emit_raw.zig new file mode 100644 index 0000000000..54ceae3263 --- /dev/null +++ b/lib/std/build/emit_raw.zig @@ -0,0 +1,255 @@ +const std = @import("std"); + +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const ArrayList = std.ArrayList; +const Builder = std.build.Builder; +const File = std.fs.File; +const InstallDir = std.build.InstallDir; +const LibExeObjStep = std.build.LibExeObjStep; +const Step = std.build.Step; +const elf = std.elf; +const fs = std.fs; +const io = std.io; +const sort = std.sort; +const warn = std.debug.warn; + +const BinOutStream = io.OutStream(anyerror); +const BinSeekStream = io.SeekableStream(anyerror, anyerror); +const ElfSeekStream = io.SeekableStream(anyerror, anyerror); +const ElfInStream = io.InStream(anyerror); + +const BinaryElfSection = struct { + elfOffset: u64, + binaryOffset: u64, + fileSize: usize, + segment: ?*BinaryElfSegment, +}; + +const BinaryElfSegment = struct { + physicalAddress: u64, + virtualAddress: u64, + elfOffset: u64, + binaryOffset: u64, + fileSize: usize, + firstSection: ?*BinaryElfSection, +}; + +const BinaryElfOutput = struct { + segments: ArrayList(*BinaryElfSegment), + sections: ArrayList(*BinaryElfSection), + + const Self = @This(); + + pub fn init(allocator: *Allocator) Self { + return Self{ + .segments = ArrayList(*BinaryElfSegment).init(allocator), + .sections = ArrayList(*BinaryElfSection).init(allocator), + }; + } + + pub fn deinit(self: *Self) void { + self.sections.deinit(); + self.segments.deinit(); + } + + pub fn parseElf(self: *Self, elfFile: elf.Elf) !void { + const allocator = self.segments.allocator; + + for (elfFile.section_headers) |section, i| { + if (sectionValidForOutput(section)) { + const newSection = try allocator.create(BinaryElfSection); + + newSection.binaryOffset = 0; + newSection.elfOffset = section.sh_offset; + newSection.fileSize = @intCast(usize, section.sh_size); + newSection.segment = null; + + try self.sections.append(newSection); + } + } + + for (elfFile.program_headers) |programHeader, i| { + if (programHeader.p_type == elf.PT_LOAD) { + const newSegment = try allocator.create(BinaryElfSegment); + + newSegment.physicalAddress = if (programHeader.p_paddr != 0) programHeader.p_paddr else programHeader.p_vaddr; + newSegment.virtualAddress = programHeader.p_vaddr; + newSegment.fileSize = @intCast(usize, programHeader.p_filesz); + newSegment.elfOffset = programHeader.p_offset; + newSegment.binaryOffset = 0; + newSegment.firstSection = null; + + for (self.sections.toSlice()) |section| { + if (sectionWithinSegment(section, programHeader)) { + if (section.segment) |sectionSegment| { + if (sectionSegment.elfOffset > newSegment.elfOffset) { + section.segment = newSegment; + } + } else { + section.segment = newSegment; + } + + if (newSegment.firstSection == null) { + newSegment.firstSection = section; + } + } + } + + try self.segments.append(newSegment); + } + } + + sort.sort(*BinaryElfSegment, self.segments.toSlice(), segmentSortCompare); + + if (self.segments.len > 0) { + const firstSegment = self.segments.at(0); + if (firstSegment.firstSection) |firstSection| { + const diff = firstSection.elfOffset - firstSegment.elfOffset; + + firstSegment.elfOffset += diff; + firstSegment.fileSize += diff; + firstSegment.physicalAddress += diff; + + const basePhysicalAddress = firstSegment.physicalAddress; + + for (self.segments.toSlice()) |segment| { + segment.binaryOffset = segment.physicalAddress - basePhysicalAddress; + } + } + } + + for (self.sections.toSlice()) |section| { + if (section.segment) |segment| { + section.binaryOffset = segment.binaryOffset + (section.elfOffset - segment.elfOffset); + } + } + + sort.sort(*BinaryElfSection, self.sections.toSlice(), sectionSortCompare); + } + + fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.ProgramHeader) bool { + return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize); + } + + fn sectionValidForOutput(section: elf.SectionHeader) bool { + return section.sh_size > 0 and section.sh_type != elf.SHT_NOBITS and ((section.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC); + } + + fn segmentSortCompare(left: *BinaryElfSegment, right: *BinaryElfSegment) bool { + if (left.physicalAddress < right.physicalAddress) { + return true; + } + if (left.physicalAddress > right.physicalAddress) { + return false; + } + return false; + } + + fn sectionSortCompare(left: *BinaryElfSection, right: *BinaryElfSection) bool { + return left.binaryOffset < right.binaryOffset; + } +}; + +const WriteContext = struct { + inStream: *ElfInStream, + inSeekStream: *ElfSeekStream, + outStream: *BinOutStream, + outSeekStream: *BinSeekStream, +}; + +fn writeBinaryElfSection(allocator: *Allocator, context: WriteContext, section: *BinaryElfSection) !void { + var readBuffer = try allocator.alloc(u8, section.fileSize); + defer allocator.free(readBuffer); + + try context.inSeekStream.seekTo(section.elfOffset); + _ = try context.inStream.read(readBuffer); + + try context.outSeekStream.seekTo(section.binaryOffset); + try context.outStream.write(readBuffer); +} + +fn emit_raw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void { + var arenaAlloc = ArenaAllocator.init(allocator); + errdefer arenaAlloc.deinit(); + var arena_allocator = &arenaAlloc.allocator; + + const currentDir = fs.cwd(); + + var file = try currentDir.openFile(elf_path, File.OpenFlags{}); + defer file.close(); + + var fileInStream = file.inStream(); + var fileSeekStream = file.seekableStream(); + + var elfFile = try elf.Elf.openStream(allocator, @ptrCast(*ElfSeekStream, &fileSeekStream.stream), @ptrCast(*ElfInStream, &fileInStream.stream)); + defer elfFile.close(); + + var outFile = try currentDir.createFile(raw_path, File.CreateFlags{}); + defer outFile.close(); + + var outFileOutStream = outFile.outStream(); + var outFileSeekStream = outFile.seekableStream(); + + const writeContext = WriteContext{ + .inStream = @ptrCast(*ElfInStream, &fileInStream.stream), + .inSeekStream = @ptrCast(*ElfSeekStream, &fileSeekStream.stream), + .outStream = @ptrCast(*BinOutStream, &outFileOutStream.stream), + .outSeekStream = @ptrCast(*BinSeekStream, &outFileSeekStream.stream), + }; + + var binaryElfOutput = BinaryElfOutput.init(arena_allocator); + defer binaryElfOutput.deinit(); + + try binaryElfOutput.parseElf(elfFile); + + for (binaryElfOutput.sections.toSlice()) |section| { + try writeBinaryElfSection(allocator, writeContext, section); + } +} + +pub const InstallRawStep = struct { + step: Step, + builder: *Builder, + artifact: *LibExeObjStep, + dest_dir: InstallDir, + dest_filename: [] const u8, + + const Self = @This(); + + pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: [] const u8) *Self { + const self = builder.allocator.create(Self) catch unreachable; + self.* = Self{ + .step = Step.init(builder.fmt("install raw binary {}", .{artifact.step.name}), builder.allocator, make), + .builder = builder, + .artifact = artifact, + .dest_dir = switch (artifact.kind) { + .Obj => unreachable, + .Test => unreachable, + .Exe => .Bin, + .Lib => unreachable, + }, + .dest_filename = dest_filename, + }; + self.step.dependOn(&artifact.step); + + builder.pushInstalledFile(self.dest_dir, dest_filename); + return self; + } + + fn make(step: *Step) !void { + const self = @fieldParentPtr(Self, "step", step); + const builder = self.builder; + + if (self.artifact.target.getObjectFormat() != .elf) { + warn("InstallRawStep only works with ELF format.\n", .{}); + return error.InvalidObjectFormat; + } + + const full_src_path = self.artifact.getOutputPath(); + const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename); + + fs.makePath(builder.allocator, builder.getInstallPath(self.dest_dir, "")) catch unreachable; + try emit_raw(builder.allocator, full_src_path, full_dest_path); + } +}; \ No newline at end of file diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 3af2a5c417..a87dbe292d 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -946,8 +946,8 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section { const elf_header = (try elf_file.findSection(name)) orelse return null; return DwarfInfo.Section{ - .offset = elf_header.offset, - .size = elf_header.size, + .offset = elf_header.sh_offset, + .size = elf_header.sh_size, }; } @@ -987,12 +987,12 @@ pub fn openElfDebugInfo( var di = DwarfInfo{ .endian = efile.endian, - .debug_info = (data[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)]), - .debug_abbrev = (data[@intCast(usize, debug_abbrev.offset)..@intCast(usize, debug_abbrev.offset + debug_abbrev.size)]), - .debug_str = (data[@intCast(usize, debug_str.offset)..@intCast(usize, debug_str.offset + debug_str.size)]), - .debug_line = (data[@intCast(usize, debug_line.offset)..@intCast(usize, debug_line.offset + debug_line.size)]), + .debug_info = (data[@intCast(usize, debug_info.sh_offset)..@intCast(usize, debug_info.sh_offset + debug_info.sh_size)]), + .debug_abbrev = (data[@intCast(usize, debug_abbrev.sh_offset)..@intCast(usize, debug_abbrev.sh_offset + debug_abbrev.sh_size)]), + .debug_str = (data[@intCast(usize, debug_str.sh_offset)..@intCast(usize, debug_str.sh_offset + debug_str.sh_size)]), + .debug_line = (data[@intCast(usize, debug_line.sh_offset)..@intCast(usize, debug_line.sh_offset + debug_line.sh_size)]), .debug_ranges = if (opt_debug_ranges) |debug_ranges| - data[@intCast(usize, debug_ranges.offset)..@intCast(usize, debug_ranges.offset + debug_ranges.size)] + data[@intCast(usize, debug_ranges.sh_offset)..@intCast(usize, debug_ranges.sh_offset + debug_ranges.sh_size)] else null, }; diff --git a/lib/std/elf.zig b/lib/std/elf.zig index dc1638c5cb..9e4c1ac5f6 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -330,19 +330,8 @@ pub const ET = extern enum(u16) { pub const HIPROC = 0xffff; }; -/// TODO delete this in favor of Elf64_Shdr -pub const SectionHeader = struct { - name: u32, - sh_type: u32, - flags: u64, - addr: u64, - offset: u64, - size: u64, - link: u32, - info: u32, - addr_align: u64, - ent_size: u64, -}; +pub const SectionHeader = Elf64_Shdr; +pub const ProgramHeader = Elf64_Phdr; pub const Elf = struct { seekable_stream: *io.SeekableStream(anyerror, anyerror), @@ -357,6 +346,7 @@ pub const Elf = struct { string_section_index: usize, string_section: *SectionHeader, section_headers: []SectionHeader, + program_headers: []ProgramHeader, allocator: *mem.Allocator, /// Call close when done. @@ -421,14 +411,24 @@ pub const Elf = struct { try seekable_stream.seekBy(4); const header_size = try in.readInt(u16, elf.endian); - if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { + if ((elf.is_64 and header_size != @sizeOf(Elf64_Ehdr)) or (!elf.is_64 and header_size != @sizeOf(Elf32_Ehdr))) { return error.InvalidFormat; } const ph_entry_size = try in.readInt(u16, elf.endian); const ph_entry_count = try in.readInt(u16, elf.endian); + + if ((elf.is_64 and ph_entry_size != @sizeOf(Elf64_Phdr)) or (!elf.is_64 and ph_entry_size != @sizeOf(Elf32_Phdr))) { + return error.InvalidFormat; + } + const sh_entry_size = try in.readInt(u16, elf.endian); const sh_entry_count = try in.readInt(u16, elf.endian); + + if ((elf.is_64 and sh_entry_size != @sizeOf(Elf64_Shdr)) or (!elf.is_64 and sh_entry_size != @sizeOf(Elf32_Shdr))) { + return error.InvalidFormat; + } + elf.string_section_index = @as(usize, try in.readInt(u16, elf.endian)); if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; @@ -443,47 +443,72 @@ pub const Elf = struct { return error.InvalidFormat; } + try seekable_stream.seekTo(elf.program_header_offset); + + elf.program_headers = try elf.allocator.alloc(ProgramHeader, ph_entry_count); + errdefer elf.allocator.free(elf.program_headers); + + if (elf.is_64) { + for (elf.program_headers) |*elf_program| { + elf_program.p_type = try in.readInt(Elf64_Word, elf.endian); + elf_program.p_flags = try in.readInt(Elf64_Word, elf.endian); + elf_program.p_offset = try in.readInt(Elf64_Off, elf.endian); + elf_program.p_vaddr = try in.readInt(Elf64_Addr, elf.endian); + elf_program.p_paddr = try in.readInt(Elf64_Addr, elf.endian); + elf_program.p_filesz = try in.readInt(Elf64_Xword, elf.endian); + elf_program.p_memsz = try in.readInt(Elf64_Xword, elf.endian); + elf_program.p_align = try in.readInt(Elf64_Xword, elf.endian); + } + } else { + for (elf.program_headers) |*elf_program| { + elf_program.p_type = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); + elf_program.p_offset = @as(Elf64_Off, try in.readInt(Elf32_Off, elf.endian)); + elf_program.p_vaddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian)); + elf_program.p_paddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian)); + elf_program.p_filesz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); + elf_program.p_memsz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); + elf_program.p_flags = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); + elf_program.p_align = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); + } + } + try seekable_stream.seekTo(elf.section_header_offset); elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count); errdefer elf.allocator.free(elf.section_headers); if (elf.is_64) { - if (sh_entry_size != 64) return error.InvalidFormat; - for (elf.section_headers) |*elf_section| { - elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_name = try in.readInt(u32, elf.endian); elf_section.sh_type = try in.readInt(u32, elf.endian); - elf_section.flags = try in.readInt(u64, elf.endian); - elf_section.addr = try in.readInt(u64, elf.endian); - elf_section.offset = try in.readInt(u64, elf.endian); - elf_section.size = try in.readInt(u64, elf.endian); - elf_section.link = try in.readInt(u32, elf.endian); - elf_section.info = try in.readInt(u32, elf.endian); - elf_section.addr_align = try in.readInt(u64, elf.endian); - elf_section.ent_size = try in.readInt(u64, elf.endian); + elf_section.sh_flags = try in.readInt(u64, elf.endian); + elf_section.sh_addr = try in.readInt(u64, elf.endian); + elf_section.sh_offset = try in.readInt(u64, elf.endian); + elf_section.sh_size = try in.readInt(u64, elf.endian); + elf_section.sh_link = try in.readInt(u32, elf.endian); + elf_section.sh_info = try in.readInt(u32, elf.endian); + elf_section.sh_addralign = try in.readInt(u64, elf.endian); + elf_section.sh_entsize = try in.readInt(u64, elf.endian); } } else { - if (sh_entry_size != 40) return error.InvalidFormat; - for (elf.section_headers) |*elf_section| { // TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ? - elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_name = try in.readInt(u32, elf.endian); elf_section.sh_type = try in.readInt(u32, elf.endian); - elf_section.flags = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.addr = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.offset = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.size = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.link = try in.readInt(u32, elf.endian); - elf_section.info = try in.readInt(u32, elf.endian); - elf_section.addr_align = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.ent_size = @as(u64, try in.readInt(u32, elf.endian)); + elf_section.sh_flags = @as(u64, try in.readInt(u32, elf.endian)); + elf_section.sh_addr = @as(u64, try in.readInt(u32, elf.endian)); + elf_section.sh_offset = @as(u64, try in.readInt(u32, elf.endian)); + elf_section.sh_size = @as(u64, try in.readInt(u32, elf.endian)); + elf_section.sh_link = try in.readInt(u32, elf.endian); + elf_section.sh_info = try in.readInt(u32, elf.endian); + elf_section.sh_addralign = @as(u64, try in.readInt(u32, elf.endian)); + elf_section.sh_entsize = @as(u64, try in.readInt(u32, elf.endian)); } } for (elf.section_headers) |*elf_section| { if (elf_section.sh_type != SHT_NOBITS) { - const file_end_offset = try math.add(u64, elf_section.offset, elf_section.size); + const file_end_offset = try math.add(u64, elf_section.sh_offset, elf_section.sh_size); if (stream_end < file_end_offset) return error.InvalidFormat; } } @@ -499,13 +524,14 @@ pub const Elf = struct { pub fn close(elf: *Elf) void { elf.allocator.free(elf.section_headers); + elf.allocator.free(elf.program_headers); } pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader { section_loop: for (elf.section_headers) |*elf_section| { if (elf_section.sh_type == SHT_NULL) continue; - const name_offset = elf.string_section.offset + elf_section.name; + const name_offset = elf.string_section.sh_offset + elf_section.sh_name; try elf.seekable_stream.seekTo(name_offset); for (name) |expected_c| { @@ -523,7 +549,7 @@ pub const Elf = struct { } pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void { - try elf.seekable_stream.seekTo(elf_section.offset); + try elf.seekable_stream.seekTo(elf_section.sh_offset); } }; @@ -578,6 +604,26 @@ pub const Elf64_Ehdr = extern struct { e_shnum: Elf64_Half, e_shstrndx: Elf64_Half, }; +pub const Elf32_Phdr = extern struct { + p_type: Elf32_Word, + p_offset: Elf32_Off, + p_vaddr: Elf32_Addr, + p_paddr: Elf32_Addr, + p_filesz: Elf32_Word, + p_memsz: Elf32_Word, + p_flags: Elf32_Word, + p_align: Elf32_Word, +}; +pub const Elf64_Phdr = extern struct { + p_type: Elf64_Word, + p_flags: Elf64_Word, + p_offset: Elf64_Off, + p_vaddr: Elf64_Addr, + p_paddr: Elf64_Addr, + p_filesz: Elf64_Xword, + p_memsz: Elf64_Xword, + p_align: Elf64_Xword, +}; pub const Elf32_Shdr = extern struct { sh_name: Elf32_Word, sh_type: Elf32_Word, @@ -655,26 +701,6 @@ pub const Elf64_Rela = extern struct { r_info: Elf64_Xword, r_addend: Elf64_Sxword, }; -pub const Elf32_Phdr = extern struct { - p_type: Elf32_Word, - p_offset: Elf32_Off, - p_vaddr: Elf32_Addr, - p_paddr: Elf32_Addr, - p_filesz: Elf32_Word, - p_memsz: Elf32_Word, - p_flags: Elf32_Word, - p_align: Elf32_Word, -}; -pub const Elf64_Phdr = extern struct { - p_type: Elf64_Word, - p_flags: Elf64_Word, - p_offset: Elf64_Off, - p_vaddr: Elf64_Addr, - p_paddr: Elf64_Addr, - p_filesz: Elf64_Xword, - p_memsz: Elf64_Xword, - p_align: Elf64_Xword, -}; pub const Elf32_Dyn = extern struct { d_tag: Elf32_Sword, d_un: extern union { @@ -833,6 +859,17 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct { flags2: Elf32_Word, }; +comptime { + debug.assert(@sizeOf(Elf32_Ehdr) == 52); + debug.assert(@sizeOf(Elf64_Ehdr) == 64); + + debug.assert(@sizeOf(Elf32_Phdr) == 32); + debug.assert(@sizeOf(Elf64_Phdr) == 56); + + debug.assert(@sizeOf(Elf32_Shdr) == 40); + debug.assert(@sizeOf(Elf64_Shdr) == 64); +} + pub const Auxv = switch (@sizeOf(usize)) { 4 => Elf32_auxv_t, 8 => Elf64_auxv_t, diff --git a/lib/std/target.zig b/lib/std/target.zig index 0b09ebf838..4c86d0c2a6 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -972,6 +972,23 @@ pub const Target = union(enum) { } } + pub fn getObjectFormat(self: Target) ObjectFormat { + switch (self) { + .Native => return @import("builtin").object_format, + .Cross => blk: { + if (self.isWindows() or self.isUefi()) { + return .coff; + } else if (self.isDarwin()) { + return .macho; + } + if (self.isWasm()) { + return .wasm; + } + return .elf; + }, + } + } + pub fn isMinGW(self: Target) bool { return self.isWindows() and self.isGnu(); } diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 11bb83ae11..74eff90dc8 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -31,7 +31,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) llvm.SetTarget(module, comp.llvm_triple.toSliceConst()); llvm.SetDataLayout(module, comp.target_layout_str); - if (util.getObjectFormat(comp.target) == .coff) { + if (comp.target.getObjectFormat() == .coff) { llvm.AddModuleCodeViewFlag(module); } else { llvm.AddModuleDebugInfoFlag(module); diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 96e18514ea..0a29da4778 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -76,7 +76,7 @@ pub fn link(comp: *Compilation) !void { std.debug.warn("\n", .{}); } - const extern_ofmt = toExternObjectFormatType(util.getObjectFormat(comp.target)); + const extern_ofmt = toExternObjectFormatType(comp.target.getObjectFormat()); const args_slice = ctx.args.toSlice(); { @@ -128,7 +128,7 @@ fn toExternObjectFormatType(ofmt: ObjectFormat) c.ZigLLVM_ObjectFormatType { } fn constructLinkerArgs(ctx: *Context) !void { - switch (util.getObjectFormat(ctx.comp.target)) { + switch (ctx.comp.target.getObjectFormat()) { .unknown => unreachable, .coff => return constructLinkerArgsCoff(ctx), .elf => return constructLinkerArgsElf(ctx), diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig index 85e2fc0e73..95bc72469d 100644 --- a/src-self-hosted/util.zig +++ b/src-self-hosted/util.zig @@ -32,23 +32,6 @@ pub fn getFloatAbi(self: Target) FloatAbi { }; } -pub fn getObjectFormat(target: Target) Target.ObjectFormat { - switch (target) { - .Native => return @import("builtin").object_format, - .Cross => blk: { - if (target.isWindows() or target.isUefi()) { - return .coff; - } else if (target.isDarwin()) { - return .macho; - } - if (target.isWasm()) { - return .wasm; - } - return .elf; - }, - } -} - pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { const env = self.getAbi(); const arch = self.getArch(); -- cgit v1.2.3