Divide by zero during parseFromSlice

Hey all, a very inexperienced Zig programmer and once a somewhat competent programmer here. I’m trying to make make an API call to MusicBrainz using std.http.Client.fetch() and parsing the json with std.json.parseFromSlice(). I got it to a point that I felt was a good prototype, and made a test for it. However, when running this test, I invariably run into this error happening in bytesAsSlice():

swebb@mathgta74lcfy3:~/Source/muzigbrainz> /home/swebb/.zvm/master/zig test -freference-trace=14 --test-filter iamthemorning /home/swebb/Source/muzigbrainz/src/root.zig
/home/swebb/.zvm/master/lib/std/mem.zig:4219:70: error: division by zero here causes undefined behavior
    return @as(cast_target, @ptrCast(bytes))[0..@divExact(bytes.len, @sizeOf(T))];
                                                                     ^~~~~~~~~~
referenced by:
    remap__anon_372074: /home/swebb/.zvm/master/lib/std/mem/Allocator.zig:335:28
    toOwnedSlice: /home/swebb/.zvm/master/lib/std/array_list.zig:114:32
    innerParse__anon_368926: /home/swebb/.zvm/master/lib/std/json/static.zig:483:62
    innerParse__anon_366535: /home/swebb/.zvm/master/lib/std/json/static.zig:254:42
    innerParse__anon_368905: /home/swebb/.zvm/master/lib/std/json/static.zig:363:55
    innerParse__anon_366481: /home/swebb/.zvm/master/lib/std/json/static.zig:254:42
    innerParse__anon_341775: /home/swebb/.zvm/master/lib/std/json/static.zig:363:55
    innerParse__anon_28837: /home/swebb/.zvm/master/lib/std/json/static.zig:476:78
    innerParse__anon_22342: /home/swebb/.zvm/master/lib/std/json/static.zig:254:42
    innerParse__anon_13432: /home/swebb/.zvm/master/lib/std/json/static.zig:363:55
    parseFromTokenSourceLeaky__anon_10129: /home/swebb/.zvm/master/lib/std/json/static.zig:149:33
    parseFromTokenSource__anon_7280: /home/swebb/.zvm/master/lib/std/json/static.zig:116:49
    parseFromSlice__anon_3431: /home/swebb/.zvm/master/lib/std/json/static.zig:82:32
    mbSearch: src/root.zig:42:47
    1 reference(s) hidden; use '-freference-trace=15' to see all references

Here is the relevant code being called. I have made a variety of structs in other files to help parse the json (perhaps a remnant of my OOP education), and I can provide those as necessary, I just didn’t want to clutter an already long post, and I’m getting the impression it has more to do with memory management from the code I was trying to decipher:

const Client = std.http.Client;

pub const user_agent: []const u8 = "ZuletztMBClient/0.0.1 (my_email)";

pub fn mbSearch(allocator: std.mem.Allocator, track_name: []const u8, album_name: []const u8, artist_name: []const u8) !?QR.Result {
    var client = Client{ .allocator = allocator };
    defer client.deinit();

    const query: []const u8 = try std.fmt.allocPrint(allocator, "https://musicbrainz.org/ws/2/recording/?query=\"{s}\"%20AND%20artist:\"{s}\"%20AND%20release:\"{s}\"&fmt=json", .{ track_name, artist_name, album_name });
    defer allocator.free(query);

    var mb_result = std.ArrayList(u8).init(allocator);
    errdefer mb_result.deinit();

    const response: Client.FetchResult = try client.fetch(.{ 
                        .response_storage = .{.dynamic = &mb_result }, 
                        .location = .{ .url = query }, 
                        .method = .GET, 
                        .headers = .{ .user_agent = .{ .override = user_agent } } 
});

    switch (@intFromEnum(response.status)) {
        0...299 => std.log.debug("Success", .{}),
        300...399 => {
            std.log.debug("Redirected", .{});
            return null;
        },
        400...511 => return Client.RequestError.ConnectionRefused,
        512 => {
            std.log.debug("Need to login", .{});
            return null;
        },
        else => unreachable,
    }

    const mb_result_slice = mb_result.items;

    std.log.debug("{s}", .{mb_result_slice});

    const result = try std.json.parseFromSlice(QR.Result, allocator, mb_result_slice, .{});
    defer result.deinit();

    const query_result = result.value;

    return query_result;
}

// This test is very volatile, but I think
// these params are specific enough that
// it shouldn't need changing too often
test "iamthemorning" {
    const test_alloc = std.testing.allocator;
    const track: []const u8 = "Veni Veni Emmanuel";
    const album: []const u8 = "Counting the Ghosts";
    const artist: []const u8 = "Iamthemorning";

    const search_result: ?QR.Result = try mbSearch(test_alloc, track, album, artist);
    if (search_result) |sr| {
        const result: Entities.Recording = sr.recordings.?[0];
        try testing.expect(std.mem.eql(u8, result.id, "5854a6de-af8f-4b99-8710-cb47d6436a19"));
    }
}

It seems that QR.Result might have a field who’s type is zero sized or is a slice to a zero sized type, an empty struct maybe?

I totally missed that, while I was importing a file named Alias.zig, I wasn’t importing the actual struct named Alias inside it. Thanks for the reminder to look more closely at my fields :grin:

I’ve done exactly this before, happy to help :smiley: