Runtime Error... Can anyone help?

I working on a project this is my code. It compiles fine, but when I execute the program I get a runtime error. I was wondering if anyone could help me solve this or elaborate on the next steps for fixing the problem.

Here is the source code.

const std = @import("std");

fn get(a: []const u8) ![]const u8 {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const uri = try std.Uri.parse(a);

    var client = std.http.Client{ .allocator = allocator };
    defer client.deinit();

    const server_header_buffer: []u8 = try allocator.alloc(u8, 1024 * 8);
    defer allocator.free(server_header_buffer);

    var req = try client.open(.GET, uri, .{
        .server_header_buffer = server_header_buffer,
    });
    defer req.deinit();

    try req.send();
    try req.finish();
    try req.wait();

    const body = try req.reader().readAllAlloc(allocator, 300000 * 8);
    defer allocator.free(body);

    return body;
}

pub fn main() !void {
    const res = get("https://example.com");
    std.debug.print("{any}", .{res});
}

Here is the runtime error…

{ Segmentation fault at address 0x2013a410000
C:\Users\first cash\zig-windows-x86_64-0.15.0-dev.369+1a2ceb36c\lib\std\fmt.zig:545:34: 0x7ff7ff97ccbd in formatType__anon_31602 (main.exe.obj)
                return formatType(payload, remaining_fmt, options, writer, max_depth);
                                 ^
C:\Users\first cash\zig-windows-x86_64-0.15.0-dev.369+1a2ceb36c\lib\std\fmt.zig:193:23: 0x7ff7ff96f76b in format__anon_27946 (main.exe.obj)
        try formatType(
                      ^
C:\Users\first cash\zig-windows-x86_64-0.15.0-dev.369+1a2ceb36c\lib\std\io\Writer.zig:24:26: 0x7ff7ff965222 in print__anon_27103 (main.exe.obj)
    return std.fmt.format(self, format, args);
                         ^
C:\Users\first cash\zig-windows-x86_64-0.15.0-dev.369+1a2ceb36c\lib\std\debug.zig:217:27: 0x7ff7ff96050c in print__anon_26096 (main.exe.obj)
    nosuspend stderr.print(fmt, args) catch return;
                          ^
C:\Users\first cash\Projects\stock_trader\main.zig:33:20: 0x7ff7ff95fb12 in main (main.exe.obj)
    std.debug.print("{any}", .{res});
                   ^
C:\Users\first cash\zig-windows-x86_64-0.15.0-dev.369+1a2ceb36c\lib\std\start.zig:490:53: 0x7ff7ff9605f2 in WinStartup (main.exe.obj)
    std.os.windows.ntdll.RtlExitUserProcess(callMain());
                                                    ^
???:?:?: 0x7ffbeb53e8d6 in ??? (KERNEL32.DLL)
???:?:?: 0x7ffbebf08d9b in ??? (ntdll.dll)

You are returning memory that is freed before the end of the function. I assume you added this because of the leak checking of the allocator.

Which is the second problem, you want to use this value outside of the function, but you are deiniting the GPA at the end of the function.

Generally the right approach is to create your GPA first thing in the main, so that all the memory lives long enough to be usable.

5 Likes

The program you have is a good start. The memory allocation/freeing are a bit out of order. The following is a modification of your program. It should work with pre-0.15.1 Zig.

The allocator is set up at the top level scope and passed in to each function call. Most of the allocated memory are freed up in the get() function except the returned result. It’s freed by the caller.

Cheers.


const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    {
        const allocator = gpa.allocator();

        const res = try get(allocator, "https://example.com");
        defer allocator.free(res);
        std.debug.print("{s}\n", .{res});
    }
    if (gpa.detectLeaks()) {
        std.debug.print("Memory leak detected!\n", .{});
    }
}

fn get(allocator: std.mem.Allocator, a: []const u8) ![]const u8 {
    const uri = try std.Uri.parse(a);
    var client = std.http.Client{ .allocator = allocator };
    defer client.deinit();

    const server_header_buffer: []u8 = try allocator.alloc(u8, 1024 * 8);
    // comment this out to see how memory leak is detected.
    defer allocator.free(server_header_buffer);

    var req = try client.open(.GET, uri, .{
        .server_header_buffer = server_header_buffer,
    });
    defer req.deinit();

    try req.send();
    try req.finish();
    try req.wait();

    const body = try req.reader().readAllAlloc(allocator, 300000 * 8);
    return body;
}

detectLeaks should be deinit instead, which calls detectLeaks before cleaning up the allocator. And it should be defer’d.

the above removes the need for a block for the rest of the code in main.

Also no need to print anything about memory leaks, detectLeaks will use the logger, which prints to the terminal by default, to log all the leaks.

3 Likes

Not sure if you’ve seen “idiomatic” Zig that demonstrates how it’s better than C. You should leave it up to the caller to supply an allocator.

Hey thanks so much for the advice. I have continued typing some more logic for my program and got a compiler error I simply do not understand.

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    {
        const allocator = gpa.allocator();

        const res = try get(allocator, "https://api.polygon.io/v3/reference/tickers?market=stocks&active=true&order=asc&limit=1000&sort=ticker&apiKey=123");
        defer allocator.free(res);

        const delimiter = "r:\"";
        const symbols = std.mem.splitScalar(u8, res, delimiter);
        const end_of_symbols = "\"";
        for (symbols) |symbol| {
            const ticker = std.mem.splitScalar(u8, symbol, end_of_symbols)[0];
            std.debug.print("{s}\n", .{ticker});
        }
    }
    if (gpa.detectLeaks()) {
        std.debug.print("Memory leak detected!\n", .{});
    }
}

fn get(allocator: std.mem.Allocator, a: []const u8) ![]const u8 {
    const uri = try std.Uri.parse(a);
    var client = std.http.Client{ .allocator = allocator };
    defer client.deinit();

    const server_header_buffer: []u8 = try allocator.alloc(u8, 1024 * 8);
    // comment this out to see how memory leak is detected.
    defer allocator.free(server_header_buffer);

    var req = try client.open(.GET, uri, .{
        .server_header_buffer = server_header_buffer,
    });
    defer req.deinit();

    try req.send();
    try req.finish();
    try req.wait();

    const body = try req.reader().readAllAlloc(allocator, 300000 * 8);
    return body;
}

The build time error is:

j.zig:12:54: error: expected type 'u8', found '*const [3:0]u8'
        const symbols = std.mem.splitScalar(u8, res, delimiter);
                                                     ^~~~~~~~~
C:\Users\first cash\zig-windows-x86_64-0.15.0-dev.369+1a2ceb36c\lib\std\mem.zig:2481:68: note: parameter type declared here
pub fn splitScalar(comptime T: type, buffer: []const T, delimiter: T) SplitIterator(T, .scalar) {
                                                                   ^
referenced by:
    WinStartup: C:\Users\first cash\zig-windows-x86_64-0.15.0-dev.369+1a2ceb36c\lib\std\start.zig:671:37
    comptime: C:\Users\first cash\zig-windows-x86_64-0.15.0-dev.369+1a2ceb36c\lib\std\start.zig:64:30

I am basically trying to scrape all the tickers. I get the response and then I start to parse the response with std.mem.splitScalar() function. I am a little confused on this function. I have read example on the internet but cannot figure out why this is not working. Hopefully your guy’s expertise can help me. Thanks again.

Try splitSequence.

The error is telling you exactly what the issues is: splitScalar takes a single item of the element type as a delimiter, (u8 in the example), and you’re passing it a string literal.

jumpnbrownweasel solves your problem by using the correct function for your intended use.