Why does this http client code leak memory?

I have the following piece of code:

const std = @import("std");

pub fn main() !void {
    const allocator = std.heap.page_allocator;
    try _main(allocator);
}

fn _main(allocator: std.mem.Allocator) !void {
    var client: std.http.Client = .{ .allocator = allocator };
    defer client.deinit();

    const uri = std.Uri.parse("https://example.com") catch unreachable;
    var headers = std.http.Headers.init(allocator);
    defer headers.deinit();

    var req = try client.request(.GET, uri, headers, .{});
    try req.start();
    try req.wait();
    // var body: []u8 = try req.reader().readAllAlloc(allocator, 8192);
    // defer allocator.free(body);

    // std.log.info("status: {}", .{req.response.status});
    // std.log.info("body: {s}", .{body});
}

test "test" {
    const allocator = std.testing.allocator;
    try _main(allocator);
}

If I do zig build test I get a memory leak reported:

[gpa] (err): memory address 0x7f169582a000 leaked: 
/home/jan/zig-linux-x86_64-0.11.0/lib/std/compress/deflate/dict_decoder.z
 (test)
        self.hist = try allocator.alloc(u8, size);
                                       ^
/home/jan/zig-linux-x86_64-0.11.0/lib/std/compress/deflate/decompressor.z
t (test)
            try dd.init(allocator, max_match_o
                       ^
/home/jan/zig-linux-x86_64-0.11.0/lib/std/comp
ompressor__anon_6607 (test)
    return Decompressor(@TypeOf(reader)).init(
                                             ^
/home/jan/zig-linux-x86_64-0.11.0/lib/std/comp
                .inflater = try deflate.decomp
                                              
/home/jan/zig-linux-x86_64-0.11.0/lib/std/comp
30 (test)
    return Decompress(@TypeOf(reader)).init(al
                                           ^
/home/jan/zig-linux-x86_64-0.11.0/lib/std/http
                            .gzip = std.compre
Reader()) catch return error.CompressionInitia
                                              
/home/jan/projects/Learn/zig-client/src/main.z
    try req.wait();
                ^
/home/jan/projects/Learn/zig-client/src/main.z
    try _main(allocator);
             ^
run test: error: while executing test 'test.te
/home/jan/projects/Learn/zig-client/zig-cache/
Build Summary: 1/3 steps succeeded; 1 failed; 
ne)
test transitive failure
└─ run test 1/1 passed, 1 leaked
error: the following build command failed with
/home/jan/projects/Learn/zig-client/zig-cache/
g-linux-x86_64-0.11.0/zig /home/jan/projects/L
ig-cache /home/jan/.cache/zig test

Why does this leak and how to fix it?

You have to deinitialize the request too:

defer req.deinit();

The fact that the request allocates memory should probably be made more explicit. The std.http section is relatively new, so it’s API hasn’t been iterated upon too much. It might feel a bit clunky right now.

5 Likes

Thanks, works! Update Client.zig by jw3126 · Pull Request #17254 · ziglang/zig · GitHub

1 Like