Segfault while calling another function

Python while calling zig shared library segfaults on calling internal function.

Here’s the python code

# sample.py
import ctypes
lib = ctypes.CDLL("zig-out/lib/libfasttokenizer.so")
lib.token_ranker.restype=ctypes.c_void_p


def encode(text:bytes):
    token_ranker = lib.token_ranker()


if __name__=="__main__":
    print(encode(b"Operations on vectors shorter than the target machine's native SIMD size will typically compile to single "))

Here’s the partial zig code

// src/asclib.zig
const std = @import("std");
const Rank = @import("./rank.zig");

pub export fn token_ranker() *anyopaque {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const rank = Rank.TokenRanker.from_file("scratchpad/gpt2tokens", "c100k_base", allocator) catch @panic("Cannot initialize TokenRanker");
    return @constCast(&rank);
}

// src/rank.zig
pub const TokenRanker = struct {
    str_to_id: std.StringHashMap(usize),
    id_to_str: std.HashMap(usize, []const u8, std.hash_map.AutoContext(usize), std.hash_map.default_max_load_percentage),
    tokens: [100256][]const u8,
    allocator: std.mem.Allocator,
    regex: Regex,
    const Self = @This();
    pub fn free(self: *Self) void {
        self.regex.deinit();
        self.str_to_id.deinit();
        self.id_to_str.deinit();
        for (self.tokens) |token| {
            self.allocator.free(token);
        }
    }

    pub fn from_file(comptime file_path: []const u8, comptime model_type: []const u8, allocator: std.mem.Allocator) !Self {
        const current_dir = fs.cwd();
        const file = try current_dir.openFile(file_path, .{});
        defer file.close();
        var buffer_reader = io.bufferedReader(file.reader());
        const content = try buffer_reader.reader().readAllAlloc(allocator, 5 * 1024 * 1024);
        defer allocator.free(content);
        return Self.from_string(content, model_type, allocator);
    }

    pub fn from_string(content: []const u8, comptime model_type: []const u8, allocator: std.mem.Allocator) !Self {
        std.debug.print("{d}\n", .{123});
        const Model = model.get_model(model_type);
        var tokens: [Model.n_tokens][]const u8 = undefined;
...
...

Here’s the video of the application going segfault

Here’s the repo of the whole project

Hello @akhildevelops and welcome to ziggit :slight_smile:

This is 1.6MB!

Here rank is a local variable, allocated in stack (if there is available stack space for 1.6MB).
After returning the pointer to rank, its allocation is freed.

gpa is also local, and the entire allocator is also freed when the function exits.

Try to reduce the number of tokens (e.g. to 256) to see if the crash is a stack overflow.
You need to somehow manage the memory. Using variables in functions is not enough.

2 Likes

Hello @dimdin, Thanks for the inputs. You were right the call stack went oversize because of tokens: [100256][]const u8 I refactored to store a slice instead of an array that points to static variable. Below is the partial code

pub const TokenRanker = struct {
    str_to_id: std.StringHashMap(u32),
    id_to_str: std.HashMap(u32, []const u8, std.hash_map.AutoContext(u32), std.hash_map.default_max_load_percentage),
    tokens: [][]const u8,
    allocator: std.mem.Allocator,
    regex: *const Regex.Regex,
    const Self = @This();
    pub fn free(self: *Self) void {
        // self.regex.deinit();
        self.str_to_id.deinit();
        self.id_to_str.deinit();
        for (self.tokens) |token| {
            self.allocator.free(token);
        }
    }

    pub fn from_file(comptime file_path: []const u8, comptime model_type: []const u8, allocator: std.mem.Allocator) !Self {
        const current_dir = fs.cwd();
        const file = try current_dir.openFile(file_path, .{});
        defer file.close();
        var buffer_reader = io.bufferedReader(file.reader());
        const content = try buffer_reader.reader().readAllAlloc(allocator, 5 * 1024 * 1024);
        defer allocator.free(content);
        return Self.from_string(content, model_type, allocator);
    }

    pub fn from_string(content: []const u8, comptime model_type: []const u8, allocator: std.mem.Allocator) !Self {
        // std.debug.print("{d}\n", .{123});
        const Model = model.get_model(model_type);
        const StaticTokens = struct {
            var tokens: [Model.n_tokens][]const u8 = undefined;
        };
1 Like