I am having a hard time re-implementing lines 95-103 from the C file, which should correspond to lines 61-72 in Rust. I can't seem to be able to use malloc correctly in Rust, or rather I am not able to assign new values to the allocated memory. Does anybody know how it should be done?
Why don't you just use safe code with references or indices instead of unsafe and raw pointers? The whole point of Rust is that you can't run into this kind of memory management errors if you use the safe abstractions that the language and the standard library provides.
That's because I'm working with auto-generated bindings for a C library (I used bindgen). In this library many functions require raw pointers as parameters, here's an example:
int abpoa_msa(abpoa_t *ab, abpoa_para_t *abpt, int n_seqs, char **seq_names, int *seq_lens, uint8_t **seqs, FILE *out_fp, uint8_t ***cons_seq, int ***cons_cov, int **cons_l, int *cons_n, uint8_t ***msa_seq, int *msa_l);
I get that, but this doesn't mean you have to use raw pointers everywhere. You could get temporary raw pointers at exactly the call sites of the C FFI functions, and otherwise keep using idiomatic Rust data structures.
For example, collecting a full array of raw pointers and storing them in a vector seems like an anti-pattern. If the C library requires a pointer-to-pointer, wrap it in a safe-to-use function that is short and obviously correct, in that it only hands out short-lived pointers.
Unfortunately I am running into more issues with the abpoa_msa function specified in one of my previous messages.
In the original C implementation this function takes as inputs some (uninitialized) pointers such as:
uint8_t **msa_seq;
int **cons_cov;
It then allocates the required memory, and makes the pointers point to the newly allocated memory.
I've tried to replicate that in Rust by doing this:
let msa_seq: *mut *mut *mut u8 = ptr::null_mut();
let cons_cov: *mut *mut *mut c_int = ptr::null_mut();
I 've used ptr::null_mut() because Rust explicitly requires pointers to be initialized. However, the function seems unable to modify these pointers, and trying to dereference them after the function is called results in a signal 11: SIGSEGV. Perhaps these pointers should be initialized in another way?
Also the function itself seems to be working just fine (its main output is printed on screen), the problem is that these pointers still point to 0x0000000000000000, which should be the same as ptr::null_mut().
If a function accepts a ***u8 because it needs to initialize a **u8, then it obviously wants to write through the additional level of indirection. But you are passing a null pointer, dereferencing of which is undefined behavior. You'd want to make a (possibly uninitialized or null-initialized) pointer of type **u8 and pass its address (which itself will be a valid pointer) to the function.