zig icon indicating copy to clipboard operation
zig copied to clipboard

cimport cannot cast NULL into optional function pointer

Open h4cnull opened this issue 1 year ago • 2 comments

zig version: 0.12.0

install
└─ install main
   └─ zig build-exe main Debug native 1 errors
xxx\zig-cache\o\762541bc2d17073d70cb6792c5fbd54b\cimport.zig:90966:293: error: expected type '?*const fn (?*cimport.struct__LIBSSH2_SESSION, [*c][*c]u8, [*c]c_int, [*c]?*anyopaque) callconv(.C) void', found '?*anyopaque'
pub inline fn libssh2_userauth_password(session: anytype, username: anytype, password: anytype) @TypeOf(libssh2_userauth_password_ex(session, username, @import("std").zig.c_translation.cast(c_uint, strlen(username)), password, @import("std").zig.c_translation.cast(c_uint, strlen(password)), NULL)) {                                                                                                                                                                                                    
                                                                                                                                                                                                    
^~~~
xxx\zig-cache\o\762541bc2d17073d70cb6792c5fbd54b\cimport.zig:90966:293: note: pointer type child 'anyopaque' cannot cast into pointer type child 'fn (?*cimport.struct__LIBSSH2_SESSION, [*c][*c]u8, [*c]c_int, [*c]?*anyopaque) callconv(.C) void'
xxx\zig-cache\o\762541bc2d17073d70cb6792c5fbd54b\cimport.zig:57662:182: note: parameter type declared here
pub extern fn libssh2_userauth_password_ex(session: ?*LIBSSH2_SESSION, username: [*c]const u8, username_len: c_uint, password: [*c]const u8, password_len: c_uint, passwd_change_cb: ?*const fn (?*LIBSSH2_SESSION, [*c][*c]u8, [*c]c_int, [*c]?*anyopaque) callconv(.C) void) c_int;
                                                                                                                                                                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src\main.zig:55:51: note: called from here
    const aret = libssh2.libssh2_userauth_password(session, user, pass);
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
referenced by:
    callMain: ziglang.vscode-zig\zig_install\lib\std\start.zig:511:32
    callMainWithArgs: ziglang.vscode-zig\zig_install\lib\std\start.zig:469:12
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

NULL -> ?*anyopaque, but anyopaque cannot -> fn pointer.

h4cnull avatar May 09 '24 06:05 h4cnull

Maybe I'm wrong but I doubt this bug will help solve any problems. If you want to improve it, please show how to reproduce the error, preferably with the least amount of code and dependencies. Also, show what commands you ran.

travisstaloch avatar May 09 '24 06:05 travisstaloch

A reproducible source code example, or a more detailed explanation, would be helpful.

It looks to me (and I might be wrong) like libssh2_userauth_password (originally translated from a macro) is called with third argument being *?anyopaque, which then attempts to call libssh2_userauth_password_ex with the *?anyopaque given to its sixth argument.

As the error message states, *?anyopaque does not automatically coerce to a *const fn(...) ..., but I think using @ptrCast should do the trick. Therefore if you wrap the argument given as passwd_change_cb, say x, as @ptrCast(x), it should work. Since this seems to be coming from code generated by translate-c (via @cImport), it's a translate-c bug that the @ptrCast wasn't introduced automatically.

rohlem avatar May 09 '24 09:05 rohlem

I was using libssh2 in my zig program,when i build with: zig build command,the error reported. this is the source code.

// zig main.zig
const libssh2 = @cImport(@cInclude("libssh2.h"));
....
const aret = libssh2.libssh2_userauth_password(session, user, pass);

the libssh2_userauth_password was a c macro.

// c libssh2.h
#define libssh2_userauth_password(session, username, password) \
    libssh2_userauth_password_ex((session), (username), \
                                 (unsigned int)strlen(username), \
                                 (password), (unsigned int)strlen(password), \
                                 NULL)

it translated to zig:

// zig cimport.zig
pub inline fn libssh2_userauth_password(session: anytype, username: anytype, password: anytype) @TypeOf(libssh2_userauth_password_ex(session, username, @import("std").zig.c_translation.cast(c_uint, strlen(username)), password, @import("std").zig.c_translation.cast(c_uint, strlen(password)), NULL)) {
    _ = &session;
    _ = &username;
    _ = &password;
    return libssh2_userauth_password_ex(session, username, @import("std").zig.c_translation.cast(c_uint, strlen(username)), password, @import("std").zig.c_translation.cast(c_uint, strlen(password)), NULL);
}

error reported at NULL,and the libssh2_userauth_password_ex in zig .

// zig cimport.zig
pub extern fn libssh2_userauth_password_ex(session: ?*LIBSSH2_SESSION, username: [*c]const u8, username_len: c_uint, password: [*c]const u8, password_len: c_uint, passwd_change_cb: ?*const fn (?*LIBSSH2_SESSION, [*c][*c]u8, [*c]c_int, [*c]?*anyopaque) callconv(.C) void) c_int;

the NULL not cast into the passwd_change_cb, it is a optional function pointer.

h4cnull avatar May 10 '24 04:05 h4cnull

This seems to be a minimal reproduction

/tmp/tmp.h

void foo_ex(void (*foo_cb)(int)){
  foo_cb(0);
}

#define NULL ((void*)0)
#define foo foo_ex(NULL)

/tmp/tmp.zig

const c = @cImport(@cInclude("/tmp/tmp.h"));
test "doesn't compile" {
    _ = c.foo;
}
test "compiles" {
    _ = c.foo_ex(@ptrCast(c.NULL));
}
$ zig test /tmp/tmp.zig
.../zig-cache/o/ee1809ebd18e6d2b9c2d15525fe76df2/cimport.zig:489:24: error: expected type '?*const fn (c_int) callconv(.C) void', found '?*anyopaque'
pub const foo = foo_ex(NULL);
                       ^~~~
.../zig-cache/o/ee1809ebd18e6d2b9c2d15525fe76df2/cimport.zig:489:24: note: pointer type child 'anyopaque' cannot cast into pointer type child 'fn (c_int) callconv(.C) void'
.../zig-cache/o/ee1809ebd18e6d2b9c2d15525fe76df2/cimport.zig:57:34: note: parameter type declared here
pub export fn foo_ex(arg_foo_cb: ?*const fn (c_int) callconv(.C) void) void {
                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

travisstaloch avatar May 10 '24 05:05 travisstaloch

Duplicate of #5596

Vexu avatar Aug 18 '24 18:08 Vexu