Bindgen generate Options and some are None

Hi All,

I got a small issue using bindgen.

Bindgen is used to generate binding from this file: https://github.com/RedisLabs/RedisModulesSDK/blob/master/redismodule.h

The problem is that all the function generated are wrapped in an Option, like this:

extern "C" {
    #[link_name = "RedisModule_Alloc"]
    pub static mut RedisModule_Alloc:
               ::std::option::Option<unsafe extern "C" fn(bytes: usize)
                                         -> *mut ::std::os::raw::c_void>;
}
extern "C" {
    #[link_name = "RedisModule_Realloc"]
    pub static mut RedisModule_Realloc:
               ::std::option::Option<unsafe extern "C" fn(ptr:
                                                              *mut ::std::os::raw::c_void,
                                                          bytes: usize)
                                         -> *mut ::std::os::raw::c_void>;
}
extern "C" {
    #[link_name = "RedisModule_Free"]
    pub static mut RedisModule_Free:
               ::std::option::Option<unsafe extern "C" fn(ptr:
                                                              *mut ::std::os::raw::c_void)>;
}

Up until now it was not a problem since I simply unwraped the function and use it.

Of course now I am stumble upon the fact that in some particular branch of the code, the Option actually is None and I am stuck.

I do not understand neither why bindgen generate options, what makes the None commute to the Some result and finally where all this happen in the code.

Some of you with more experience has already found a similar issues?

Now the code is a little more complex than my previous description, we are compiling a shared object .so that will be used by redis. And again the part of the code that is having the issues is executed in a different thread.

Thanks,

1 Like

They’re Options because that header file defines them as function pointers, which appear to be initialized in the RedisModule_Init function (what does the bindgen code look like for it?). This function, in turn, needs to be called in the OnLoad function, which is where Redis loads your module and allows you to hook in. How are you doing all of that?

As for another thread, note that these Options are static mut. I’m not sure how bindgen installs (sets) these values, but you’d likely need to make sure there’s a fence after setting the values and before a different thread accesses them. Are the values you’re seeing as None on other thread(s) Some on the main thread?

1 Like

So it is going to check if the pointer is null, if it is actually null it return None otherwise Some, correct?

That is correct, overall I have defined another header file that looks like this:

// a symbol. Export a version under a slightly different name so that we can
// get access to it from Rust.
int Export_RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) {
    return RedisModule_Init(ctx, name, ver, apiver);
}

RedisModuleKey* Export_RedisModule_OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode){
    return RedisModule_OpenKey(ctx, keyname, mode);
}

Which generate the following code using bindgen:

extern "C" {
    pub fn Export_RedisModule_Init(ctx: *mut RedisModuleCtx,
                                   name: *const ::std::os::raw::c_char,
                                   ver: ::std::os::raw::c_int,
                                   apiver: ::std::os::raw::c_int)
     -> ::std::os::raw::c_int;
}
extern "C" {
    pub fn Export_RedisModule_OpenKey(ctx: *mut RedisModuleCtx,
                                      keyname: *mut RedisModuleString,
                                      mode: ::std::os::raw::c_int)
     -> *mut RedisModuleKey;
}

This I believe is done correctly: https://github.com/RedBeardLab/rediSQL/blob/master/src/lib.rs#L627

Not sure to follow you here.

Anyway the new thread is started after a command is being executed. (So definitely pass quite some seconds).
Honestly I see the None only on different thread from the main one, but only on some specific function, is that possible?

Thanks for your help!

Right.

Which function? Can you point to that code path?

Hi Vitaly,

sorry it took me a while to reply but I really was too tired yesterday.

I just upload the code on github with some more test.

Let me explain the code path.

When a particular command is called REDISQL.CREATE_DB a new database get created and along with it we also spawn a new thread that use a loop to listen to all the command concerning such database.

The loop: https://github.com/siscia/rediSQL/blob/splitting/src/redis.rs#L392

Inside the loop we listen for commands, each one get executed against the database and the we call the function return_value (https://github.com/siscia/rediSQL/blob/splitting/src/redis.rs#L402)

return_value (https://github.com/siscia/rediSQL/blob/splitting/src/redis.rs#L341) should execute the code commented, but most functions are None.

A possible execution looks like this:

Get None 1                                                        
Get None 2                                                        
ok                                                                
Get None 4                                                   
Get None 5     

Do you have any idea about this weird behaviour?

Thanks,

Simone

Vitaly,

I believe I understood the problem.

Those functions were introduced in a later version of Redis, and the one that I was using for test doesn't have them.

I tried the last version and this seems to solve the issues.

Thanks fore reading me and guide me through a solution :slight_smile:

Cheers, :beers:

Ah ok, good to know :+1: