I’m trying to call a routine in a C library. The C library is this one: Index of /software/libidn/libidn2 The routine I want to use is idn2_to_ascii_8z, documented in Libidn2 2.3.4 As you can see, it will write in the parameter named output. There is an example in C Libidn2 2.3.4 but note that, unlike what the documentation requests, the variable named p is not allocated (and the C example works nevertheless).
Zig sees this routine as pub extern fn idn2_to_ascii_8z(input: [*c]const u8, output: [*c][*c]u8, flags: c_int) c_int; I’m quite lost about how to call that and I find no examples on various Zig forums. This code compiles:
var dest = try allocator.alloc(u8, maxsize);
const result = idn2.idn2_to_ascii_8z(orig, @alignCast(@ptrCast(&dest)), 0);
but segfaults. I tried different variants but without any success. Any example of calling a routine with [*c][*c]u8 parameters?
the way I understood the documentation is that it’s the C function that will allocate the memory for the output. You just have to declare a viariable to hold the pointer to the new memory the C function will create.
var output: [*:0]u8 = undefined;
// then pass &output to the function
For freeing you will have to use malloc (ie the C allocator), which you can get by adding stdlib.h to your imports. Zig also exposes it from the stdlib but that interface requires you to pass in Zig slices, not just pointers-to-many, and that might make things awkward for you.
In any case, start by making the first part work and then think about freeing memory later.
Well, it still segfaults. I wonder if the problem is not instead with the input parameter. I passed the working C example through zig translate-c , it still works but when I try to write a Zig program doing the same, it segfaults. Here is a minimum example:
I tested the above code on an amd64 machine and it worked fine.
Maybe you can run it through a debugger and see exactly where it segfaults?
EDIT: I missed the fact you are running on a recent nightly, while I was testing this on the 0.11 stable release of Zig. Nevertheless, I just tested it with the most recently nightly and it still works for me:
When building, rather than zig build-exe tmp.zig -lidn2, try zig build-exe tmp.zig -lc -lidn2 to explicitly link libc. With the former command, it segfaults for me as well, but with the latter command, it works.
Unfortunately, the backtrace I get from LLDB is not helpful for this particular segfault (GDB’s is no better either):
⬢[ian@toolbox tmp]$ lldb tmp
(lldb) target create "tmp"
Current executable set to '/var/home/ian/tmp/tmp' (x86_64).
(lldb) r
Process 123849 launched: '/var/home/ian/tmp/tmp' (x86_64)
Process 123849 stopped
* thread #1, name = 'tmp', stop reason = signal SIGSEGV: address not mapped to object (fault address: 0x0)
frame #0: 0x0000000000000000
error: memory read failed for 0x0
(lldb) bt
* thread #1, name = 'tmp', stop reason = signal SIGSEGV: address not mapped to object (fault address: 0x0)
* frame #0: 0x0000000000000000
Indeed, it works, many thanks. (Alternative: add exe.linkLibC(); to build.zig.) What is strange is that there is no error message when running zig build...