Casting an *mut *mut c_void to struct - bug or lack of knowledge?

Hey folks, I think this just because I'm not really familiar with C or Unsafe Rust code, but would like to make sure.

Given that I have a function that returns *mut *mut c_void, and then cast the result of that function like so fun().cast::<ngx_http_core_loc_conf_t>(), that turned it into a *mut ngx_http_core_loc_conf_t instead a *mut *mut ngx_http_core_loc_conf_t, which eventually resulted in a segfault. I fixed that by de-referencing the pointer in the function, so it now returns *mut c_void instead, and cast returns a *mut ngx_http_core_loc_conf_t, but this time it's actually right about that.

Is this is a bug, or have I simply failed to understand how casting pointers works? Should I have tried to cast it like this cast::<*mut ngx_http_core_loc_conf_t>() instead? Is using cast the right approach, or is it considered more "standard" use as *mut *mut ngx_http_core_loc_conf_t, say?

For clarity, I've historically been a Java programmer, and this is my first foray into serious C/Rust FFI work.

The cast::<U>() method takes an *mut T and converts it to an *mut U, no matter what T is. In your case, T happened to be an *mut c_void, so you got the behavior that you saw.

Using .cast::<*mut ngx_http_core_loc_conf_t>() is fine. Another option that you might find clearer is this:

let ptr: *mut *mut ngx_http_core_loc_conf_t = old_ptr as _;
2 Likes

OK, that's interesting. I would have expected T to be c_void or *mut *mut c_void, so I think I need to re-read the pointer and type docs. Thanks!

<*mut T>::cast<U>() returns *mut U independent of T, so if U == ngx_http_core_loc_conf_t, then <*mut T>::cast<U>() returns *mut ngx_http_core_loc_conf_t. Simple as that, it immediately follows from the signature.

2 Likes