Hello! I’m currently trying to create a custom VFS for SQLite, which requires “subclassing” the vfs object. I’ve ended up with a zig struct that looks like this:
pub const sqlite3_vfs = extern struct {
iVersion: c_int = 3,
szOsFile: c_int = @sizeOf(file_types.vfs_file),
mxPathname: c_int, //max path size
pNext: ?*anyopaque = null,
zName: zName_t,
pAppData: ?*anyopaque = null,
xOpen: *const @TypeOf(xOpen) = xOpen,
// etc...
};
Followed by the function definitions, e.g.:
pub export fn xOpen(self: *sqlite3_vfs, filename: zName_t, file: *file_types.sqlite3_file, flags: c_int, out_flags: *c_int) callconv(.c) c_int {
_ = self;
_ = filename;
file.* = file_types.file_instance;
out_flags.* = flags;
return SQLITE_OK;
}
// etc...
The vfs is instantiated as a global variable, which gets registered with SQLite:
var vfs_instance = sqlite3_vfs{
.mxPathname = 200,
.zName = @constCast("embeddable"),
};
export fn sqlite3_sqliteembeddablevfs_init(_: *anyopaque, _: *anyopaque, pApi: *sqlite3_api.sqlite3_api_routines) c_int {
if(pApi.vfs_register(&vfs_instance, 1) == SQLITE_OK) {
return SQLITE_OK_LOAD_PERMANENTLY;
} else {
return SQLITE_ERR;
}
}
This seems to work mostly fine, except that if I use the “export” keyword on another function later in the file (I would also like to export xFullPathname, for instance), earlier functions will be passed completely garbage data.
- If I only export
xOpen, it’s called with the correct arguments - If I export
xOpenandxFullPathname,xFullPathnamewill be called correctly, butxOpengets garbage. - If I export a function after
xFullPathname,xFullPathnameandxOpenboth get garbage.
The backtrace looks normal up until the function is actually called.
#0 0x00007ff2dc7e8e35 in main.xFullPathname (self=0x55c28100ed10,
filename=0x7ffc38922230 "\340\"\2228\374\177", nOut=-1202594056,
zOut=0x55c280ddafdf <sqlite3OsFullPathname+59> "\311\303UH\211\345H\203\354\020H\211}\370H\211u\360H\203", <incomplete sequence \360>) from ../zig-out/lib/libsqlite_embeddable_vfs.so
#1 0x000055c280ddafdf in sqlite3OsFullPathname (pVfs=0x7ff2dc850640 <main.vfs_instance>,
zPath=0x55c2b84abdec "scratch.db", nPathOut=201, zPathOut=0x55c2b851f228 "")
at sqlite3.c:27528
#2 0x000055c280e06a13 in sqlite3PagerOpen (pVfs=0x7ff2dc850640 <main.vfs_instance>,
ppPager=0x55c2b851be88, zFilename=0x55c2b84abdec "scratch.db", nExtra=136, flags=0,
vfsFlags=262, xReinit=0x55c280e194c2 <pageReinit>) at sqlite3.c:64408
#3 0x000055c280e19cf6 in sqlite3BtreeOpen (pVfs=0x7ff2dc850640 <main.vfs_instance>,
zFilename=0x55c2b84abdec "scratch.db", db=0x55c2b851b858, ppBtree=0x55c2b851bb10,
flags=0, vfsFlags=262) at sqlite3.c:75829
#4 0x000055c280f2df3c in openDatabase (zFilename=0x55c2b851def8 "scratch.db",
ppDb=0x7ffc38924330, flags=6, zVfs=0x0) at sqlite3.c:190797
#5 0x000055c280f2e2a8 in sqlite3_open_v2 (filename=0x55c2b851def8 "scratch.db",
ppDb=0x7ffc38924330, flags=6, zVfs=0x0) at sqlite3.c:190920
#6 0x000055c280db6f06 in open_db (p=0x7ffc38924330, openFlags=1) at shell.c:29038
#7 0x000055c280dc914c in do_meta_command (zLine=0x55c2b851fd00 ".open scratch.db",
p=0x7ffc38924330) at shell.c:34804
#8 0x000055c280dd130e in process_input (p=0x7ffc38924330, zSrc=0x55c280fc62bb "<stdin>")
at shell.c:37003
#9 0x000055c280dd4669 in main (argc=1, argv=0x7ffc38925a68) at shell.c:38138
Does anyone have any ideas? I don’t have much experience working with the C ABI.