How to test for double frees

GeneralPurposeAllocator does have support for detecting double frees:

but it needs the GeneralPurposeAllocator.Config to have retain_metadata = true and never_unmap = true:

Test code:

const std = @import("std");

test "double free" {
    var gpa = std.heap.GeneralPurposeAllocator(.{
        .safety = true,
        .never_unmap = true,
        .retain_metadata = true,
    }){};
    defer std.debug.assert(gpa.deinit() == .ok);
    const allocator = gpa.allocator();

    const alloc = try allocator.alloc(u8, 8);
    allocator.free(alloc);
    allocator.free(alloc);
}

For me on Windows this is outputting:

[gpa] (err): Double free detected. Allocation:
 First free:
 Second free:
C:\Users\Ryan\Programming\Zig\tmp\doublefree.zig:10:19: 0x7510f5 in test.double free (test.exe.obj)
    allocator.free(alloc);
                  ^
C:\Users\Ryan\Programming\Zig\zig\lib\compiler\test_runner.zig:158:25: 0x75bc1a in mainTerminal (test.exe.obj)
        if (test_fn.func()) |_| {
                        ^
C:\Users\Ryan\Programming\Zig\zig\lib\compiler\test_runner.zig:35:28: 0x751998 in main (test.exe.obj)
        return mainTerminal();
                           ^
C:\Users\Ryan\Programming\Zig\zig\lib\std\start.zig:350:53: 0x751713 in WinStartup (test.exe.obj)
    std.os.windows.ntdll.RtlExitUserProcess(callMain());
                                                    ^
???:?:?: 0x7ff91a157343 in ??? (KERNEL32.DLL)
???:?:?: 0x7ff91c0e26b0 in ??? (ntdll.dll)

unsure if the first free stack trace being empty is a Windows-only bug or a general regression.

(note: it looks like I may have accidentally regressed retain_metadata in GeneralPurposeAllocator: Considerably improve worst case performance by squeek502 · Pull Request #17383 · ziglang/zig · GitHub; if there are two allocations of 8 bytes in the above test, it hits an assertion failure during gpa.deinit())

6 Likes